我不确定这是GCC编译器的错误还是预期的行为noexcept
.
请考虑以下示例:
struct B {
B(int) noexcept { }
virtual void f() = 0;
};
struct D: public B {
using B::B;
D() noexcept(noexcept(D{42})): B{42} { }
void f() override { }
};
int main() {
B *b = new D{};
}
Run Code Online (Sandbox Code Playgroud)
如果noexcept
删除它,它编译.
无论如何,正如在例子中,我从GCC v5.3.1得到了这个错误:
test.cpp:8:31: error: invalid use of incomplete type ‘struct D’
D() noexcept(noexcept(D{42})): B{42} { }
^
Run Code Online (Sandbox Code Playgroud)
据我所知,struct D
不是一个不完整的类型,但继承构造函数涉及到语句,看起来编译器实际上考虑的是基本结构的完整性而B
不是D
.
这是预期的行为还是合法代码?
为清楚起见:
请考虑以下最小示例:
#include<cstddef>
template<std::size_t... I>
constexpr auto sum() { return (I + ...); }
template<bool... B>
constexpr auto check() { return (B && ...); }
int main() {
static_assert(6 == sum<1,2,3>(), "!");
// static_assert(0 == sum<>(), "!");
static_assert(check<true, true>(), "!");
static_assert(check<>(), "!");
}
Run Code Online (Sandbox Code Playgroud)
注释行不编译.
这同样适用于*
代替+
.
涉及布尔运算的那个相反.
这里(工作草案)我没有找到关于空参数包的提及.
另一方面,这里(isocpp)似乎是上面例子中的默认结果int()
.
混合折叠表达式和空参数包时,预期的行为是什么?
我发现一个问题,我猜是由于GCC中的一个错误.
无论如何,在开启问题之前,我想确定一下.
请考虑以下代码:
#include<algorithm>
#include<list>
template<typename U>
struct S {
using FT = void(*)();
struct T { FT func; };
template<typename>
static void f() { }
std::list<T> l{ { &f<int> }, { &f<char> } };
void run() {
l.remove_if([](const T &t) { return t.func == &f<int>; }); // (1)
l.remove_if([](const auto &t) { return t.func == &f<int>; }); // (2)
}
};
int main() {
S<void> s;
s.run();
}
Run Code Online (Sandbox Code Playgroud)
我在基于SDL2构建的本机应用程序中使用C++ SDK for Google Play Game Services.本机部分是在运行时加载的.so文件.
只要我以标准方式使用应用程序,一切正常.另一方面,我遇到了gpg::GameServices
使用多窗口时遇到的问题.
当应用程序切换到多窗口模式时,本机部分将离开该main
功能并通过设计重新输入.main
由于用户正在终止应用程序或者因为切换到多窗口模式,我不知道该函数是否被放弃,因此在函数结束时我gpg::GameServices
按照文档中的建议重置指向对象的指针.然后在同一函数的开头重新初始化.
但是,看起来出现了问题,应用程序只是通过以下消息冻结了一段时间:
V/GamesNativeSDK:GameServices清理时间超过15秒或返回错误.在GameServicesImpl可能仍处于活动状态时销毁对象.
20秒后,应用程序按预期再次启动,但这种冻结非常烦人,我无法理解是什么原因.
作为旁注,出于明显的原因打电话Flush
或FlusBlocking
不解决问题(我这样做只是为了检查是否是这种情况).
gpg::GameServices
即使应用程序未正确关闭,是否有任何问题终止?我的意思是,当活动被销毁但.so没有被丢弃时,而是创建一个新的活动,并在main
之后立即再次调用该函数?
请考虑以下示例:
#include <cstring>
#include <type_traits>
#include <cassert>
int main() {
std::aligned_storage_t<sizeof(void*), alignof(void*)> storage, copy;
int i = 42;
std::memcpy(&storage, &i, sizeof(int));
copy = storage;
int j{};
std::memcpy(&j, ©, sizeof(int));
assert(j == 42);
}
Run Code Online (Sandbox Code Playgroud)
这适用于(对某些作品的定义).但是,标准告诉我们这个:
对于任何对象平凡复制的类型的(比基类的其他子对象)
T
时,对象是否保持类型的有效的值T
,构成对象的底层字节可以被复制到的阵列char
,unsigned char
或std?::?byte
.
如果将该数组的内容复制回对象,则该对象应随后保持其原始值.[例如:Run Code Online (Sandbox Code Playgroud)#define N sizeof(T) char buf[N]; T obj; // obj initialized to its original value std::memcpy(buf, &obj, N); // between these two calls to std?::?memcpy, …
在这个问题中,我将参考我之前的问题.
在那个问题中,我发现以下内容无效:
template<typename T, typename... A, typename S>
class C { };
Run Code Online (Sandbox Code Playgroud)
这是因为:
[它不是有效的代码]用于类模板,因为必须始终指定它们的参数,这将始终导致歧义,除非参数包在最后并且填充任何剩余的模板参数.
这是有道理的,当然,我得到了它.
然后,作为替代方法,提出了涉及专业化的以下内容:
template<typename F, typename S>
class C;
template<typename T, typename... A, typename S>
class C<T(A...), S> { };
Run Code Online (Sandbox Code Playgroud)
实际上,它似乎有效,所以感谢提出它的人.
无论如何,我不明白为什么这是有效的代码,而前一个不是.
它是否应该受到先前解决方案的模糊性的影响?在这种情况下,编译器为什么以及如何解决这种模糊性?
根据上一个问题(参见本问题开头的链接),在我看来,仍然可变参数部分应该将任何参数填充到最后,因此该代码也不应该是有效的.
当然,我错了,但在我的推理中究竟出了什么问题?
我需要禁用复制赋值运算符.这将有效:
A& operator=(const A&);
Run Code Online (Sandbox Code Playgroud)
如果我没有指定确切的参数,它会工作operator=
吗?
我的意思是这样的:
void operator=(void);
Run Code Online (Sandbox Code Playgroud)
返回值是正确的,我可以写任何我想要的,但参数类型怎么样?
这会覆盖operator=
类的默认值吗?
这是问题的一个后续:什么是void()
中decltype(void())
意味着什么?.
decltype(void())
编译好,void()
在这种情况下的手段在上述问题中解释(实际上在答案中).
另一方面,我注意到decltype(void{})
没有编译.
它们之间有什么区别(decltype
至少在上下文中)?
为什么第二个表达式不能编译?
为了完整起见,它遵循一个最小的(不是)工作示例:
int main() {
// this doesn't compile
//decltype(void{}) *ptr = nullptr;
// this compiles fine
decltype(void()) *ptr = nullptr;
(void)ptr;
}
Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
#include <memory>
struct Foo { std::unique_ptr<Foo> next; };
void f(Foo &foo) { foo = std::move(*foo.next); }
int main() {
Foo foo{};
foo.next = std::make_unique<Foo>();
foo.next->next = std::make_unique<Foo>();
f(foo);
}
Run Code Online (Sandbox Code Playgroud)
通过这样做foo = std::move(*foo.next);
,foo.next.next
被移动到foo.next
.
如果foo.next
作为第一步失效,则可以立即删除它指向的对象.这将导致删除foo.next.next
,这是我试图移动的对象foo.next
.
我很确定我在推理中遗漏了一些东西,但我无法弄清楚出了什么问题.
这是安全的操作吗?标准在哪里让我放心?
请考虑以下代码段:
struct S {
S() {}
template<typename B>
struct T {
T(B &&) {}
};
template<typename B>
T(B &&) -> T<B>;
};
int main() {
S::T t{0};
}
Run Code Online (Sandbox Code Playgroud)
prog.cc:10:5:错误:演绎指南'S :: T(B &&) - > S :: T'必须在命名空间范围内声明
这是有效的代码吗?哪个编译器是对的,GCC还是Clang?
c++ templates language-lawyer template-argument-deduction c++17