eiv*_*our 6 c++ using explicit-constructor language-lawyer
我使用 g++ 6.3.0 和 -std=c++14 选项编译了下面的代码。
#include <utility>
#include <iostream>
struct A{
int x;
A(const A&)=default;
A(int x):x(x){}
};
struct B{
A a;
template<class... Args>
B(Args&&... args):a(std::forward<Args>(args)...){
std::cout<<"1!"<<std::endl;
}
explicit B(const A& a):a(a){std::cout<<"2!"<<std::endl;}
};
struct C:B{
using B::B;
};
int main(){
A a{2};
const A& aref=a;
C c=aref; //Implicit conversion
}
Run Code Online (Sandbox Code Playgroud)
我预计它会输出“1!” 因为转换是隐式的,但它输出“2!”。如果我注释掉模板构造函数,它将无法编译。这是正确的行为,还是某种 g++ bug?
是的,你的程序将打印1!
.
显示编译器分歧的程序的简化版本是
struct B {
int b;
constexpr B(auto) { b = 1; }
constexpr explicit B(int) { b = 2; }
};
struct C : B {
using B::B;
};
constexpr B b = 0;
static_assert( b.b == 1 ); //ok everywhere
constexpr C c = 0;
static_assert( c.b == 1 ); //ok in Clang only
Run Code Online (Sandbox Code Playgroud)
演示: https: //gcc.godbolt.org/z/hva4f5qs5
正如相关 GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85251中引用的:[namespace.udecl] p13 确实指定了此处应该发生的情况:
在查找派生类的构造函数 ([class.qual]) 或形成一组重载候选者 ([over.match.ctor) 时,由 using 声明命名的构造函数被视为派生类的构造函数]、[over.match.copy]、[over.match.list])。
所以explicit
构造函数 fromB
应该留explicit
在C
after中using B::B;
,此时只有 Clang 能正确处理上述程序。
查看其他编译器错误的更简单方法是删除B(auto)
构造函数:
struct B {
int b;
constexpr explicit B(int) { b = 2; }
};
struct C : B {
using B::B;
};
constexpr C c = 0; // error everywhere
Run Code Online (Sandbox Code Playgroud)
现在,所有编译器都正确拒绝代码(演示: https: //gcc.godbolt.org/z/P3zqxMvvn),即使它们没有调用上一个示例中删除的构造函数。
归档时间: |
|
查看次数: |
117 次 |
最近记录: |