我正在更新一个项目以使用C ++ 17,发现一些实例,遵循该模式的代码在最新版本的clang上导致了编译错误:
#include <boost/variant.hpp>
struct vis : public boost::static_visitor<void>
{
void operator()(int) const { }
};
int main()
{
boost::variant<int> v = 0;
boost::apply_visitor(vis{}, v);
}
Run Code Online (Sandbox Code Playgroud)
在C ++ 17模式下使用clang v8.0,此操作失败,并显示以下错误:
<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
boost::apply_visitor(vis{}, v);
^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
~static_visitor() = default;
Run Code Online (Sandbox Code Playgroud)
但是,它可以在C ++ 14模式下干净地编译。我发现如果将花括号初始化更改vis{}为括号vis(),则可以在两种模式下正确编译。我尝试过的每个gcc版本都允许在C ++ 17模式下使用这两种变体。
这是从C ++ 14到C ++ 17的正确行为更改,还是这是一个叮当响的错误?如果正确,为什么现在在C ++ 17中无效(或者也许一直如此,但是clang仅在较早的标准版本中允许使用)?
选择哪个类模板特化的首选规则包括将特化重写为函数模板,并通过函数模板[temp.class.order]的排序规则确定哪个函数模板更加专业化.考虑这个例子,然后:
#include <iostream>
template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;
template <class T, class U> struct A { };
template <class T> int foo(A<T, void_t<T>> ) { return 1; }
template <class T> int foo(A<T*, void> ) { return 2; }
int main() {
std::cout << foo(A<int*, void>{});
}
Run Code Online (Sandbox Code Playgroud)
gcc和clang都打印2在这里.这是有道理的一些前面的例子-推导对非推测的情况下(void对void_t<T>)只是忽略,所以推断<T, void_t<T>>反对<X*, void>成功,但推断<T*, void>针对<Y, void_t<Y>>在两个参数失败.精细. …
添加override了C++ 11 以确保您编写的要覆盖基类虚函数的成员函数实际上(或不会编译).
但是在大型对象层次结构中,有时您可能会意外地编写一个成员函数,当您不想要它时会覆盖基类虚拟!例如:
struct A {
virtual void foo() { } // because obviously every class has foo().
};
struct B : A { ... };
class C : B {
private:
void foo() {
// was intended to be a private function local to C
// not intended to override A::foo(), but now does
}
};
Run Code Online (Sandbox Code Playgroud)
是否有一些编译器标志/扩展名至少会发出警告C::foo?为了便于阅读和正确,我只想强制所有覆盖使用override.
在此页面(http://www.cplusplus.com/reference/memory/shared_ptr/)第5段中,它说:
此外,shared_ptr对象可以在指向另一个对象的同时共享指针的所有权.此功能称为别名(请参阅构造函数),通常用于指向成员对象,同时拥有它们所属的对象.因此,shared_ptr可能与两个指针有关:
存储指针,它是指向它的指针,以及它与运算符*取消引用的指针.
一个拥有的指针(可能是共享的),它是所有权组在某个时刻负责删除的指针,并且它被视为一个用途.
通常,存储的指针和拥有的指针引用相同的对象,但是别名shared_ptr对象(使用别名构造函数及其副本构造的对象)可以引用不同的对象.
然后我读了这页(http://www.cplusplus.com/reference/memory/shared_ptr/shared_ptr/)关于shared_ptr的别名构造函数.但我仍然认为这种"走样"行为令人困惑.为什么在这里?它是为了什么?在什么情况下我想要这个功能?
我有幸遇到的最让我最喜爱/最邪恶的发明之一是constexpr计数器,也就是有状态的元编程.正如帖子中所提到的,它似乎在C++ 14下是合法的,我想知道C++ 17有什么变化吗?
以下是主要基于帖子的实现
template <int N>
struct flag
{
friend constexpr int adl_flag(flag<N>);
constexpr operator int() { return N; }
};
template <int N>
struct write
{
friend constexpr int adl_flag(flag<N>) { return N; }
static constexpr int value = N;
};
template <int N, int = adl_flag(flag<N>{})>
constexpr int read(int, flag<N>, int R = read(0, flag<N + 1>{}))
{
return R;
}
template <int N>
constexpr int read(float, flag<N>)
{
return N;
}
template <int N …Run Code Online (Sandbox Code Playgroud) 模板类std::iterator设置为在C++ 17中弃用.为什么这样?它是确保std::iterator_traits工作的一种方便方法,特别是如果您可以使用默认模板参数.在C++ 17中还有其他一些方法吗?
此函数的参数将绑定到右值引用:
void f(int && i);
Run Code Online (Sandbox Code Playgroud)
但是,此函数的参数将绑定到右值或左值引用:
template <typename T>
void f(T && t);
Run Code Online (Sandbox Code Playgroud)
我经常听到这被称为通用参考.
我也听说它被称为转发参考.
他们的意思是一样的吗?
如果函数体调用,它只是转发引用std::forward吗?
c++ templates perfect-forwarding universal-reference forwarding-reference
以下代码与GCC完全编译:
void func(int arg1, decltype(arg1) arg2)
{
(void)arg2;
}
int main(){}
Run Code Online (Sandbox Code Playgroud)
我用这个命令编译:
g++ -std=c++14 test.cpp -o test -pedantic-errors -Wall -Wextra
Run Code Online (Sandbox Code Playgroud)
但是在函数声明中间使用参数似乎很奇怪.它在标准C++中实际有效,还是GCC扩展?
我有一个标准布局联合,其中包含一大堆类型:
union Big {
Hdr h;
A a;
B b;
C c;
D d;
E e;
F f;
};
Run Code Online (Sandbox Code Playgroud)
每种类型的A直通F是标准布局和具有作为其第一元件类型的对象Hdr.该Hdr标识了工会的积极成员为,所以这是变体样.现在,我处于一种我确定知道的情况(因为我检查过),活跃成员是a B或a C.实际上,我已将空间减少到:
union Little {
Hdr h;
B b;
C c;
};
Run Code Online (Sandbox Code Playgroud)
现在,是以下明确定义还是未定义的行为?
void given_big(Big const& big) {
switch(big.h.type) {
case B::type: // fallthrough
case C::type:
given_b_or_c(reinterpret_cast<Little const&>(big));
break;
// ... other cases here ...
}
}
void given_b_or_c(Little const& little) {
if (little.h.type == B::type) {
use_a_b(little.b);
} else …Run Code Online (Sandbox Code Playgroud) 从bug 80985开始考虑这个例子:
template <class Func>
void call(Func f)
{
f();
}
void func() noexcept { }
int main()
{
call(func);
}
Run Code Online (Sandbox Code Playgroud)
正如您所做的那样,在启用所有警告的情况下进行编译会产生:
$ g++ -std=c++14 -Wall foo.cxx
foo.cxx:2:6: warning: mangled name for ‘void call(Func) [with Func = void (*)() noexcept]’ will change in C++17 because the exception specification is part of a function type [-Wnoexcept-type]
void call(Func f)
^~~~
Run Code Online (Sandbox Code Playgroud)
我应该怎么做这个警告呢?修复是什么?