Ros*_*ina 9 c++ static-assert decltype c++11
我希望以下代码失败并static_assert
检查最后一行.但是在MSVC2015和gcc 6.2中,它成功编译.它确实无法在clang 3.9中按预期编译.这是编译器错误还是static_assert
内部不起作用decltype()
?
#include <tuple>
#include <type_traits>
template<typename T>
struct Wrapper {};
template<typename T, typename U>
constexpr std::tuple<T, U> operator|(Wrapper<T>, Wrapper<U>)
{
static_assert(std::is_same<T,U>::value == false, "can't combine two of the same type");
return std::tuple<T, U> {};
}
struct A {};
struct B {};
constexpr Wrapper<A> aaa = {};
constexpr Wrapper<B> bbb = {};
constexpr auto shouldPass1 = aaa | bbb;
//constexpr auto shouldFail1 = aaa | aaa; // fails static assert as expected
using shouldFail2 = decltype(aaa | aaa);
// ^ doesn't fail in MSVC2015, or gcc 6.2. does fail in clang 3.9
Run Code Online (Sandbox Code Playgroud)
更新#1:附加问题
Brian建议static_assert
不会在decltype
上下文中触发,因为该值尚未显式实例化.所以我在下面添加了一个额外的测试来显式实例化shouldFail2
类型,我认为Brian的逻辑应该导致但是,以下代码在MSVC2015或gcc 6.2中不会失败.static_assert
失败.这是一个错误,还是我忽略了什么?编辑:看来,一旦decltype
提取了类型,我们可以自由使用shouldFail2
而无需进一步参考定义operator|
.
shouldFail2 shouldFail3 = {}; // instantiate shouldFail2.
// ^ doesn't fail in MSVC2015 or gcc 6.2.
Run Code Online (Sandbox Code Playgroud)
更新#2
如果我更改了operator|
使用没有尾随返回类型的auto
(或decltype(auto)
)的定义,那么decltype
表达式正确地使static_assert
in gcc 6.2 失败.但是,此版本无法在MSVC2015中编译(错误C3779,C2088).编辑:正如WF在下面指出的那样,省略尾随返回类型是C++ 14的一个特性.
template<typename T, typename U>
constexpr auto operator|(Wrapper<T>, Wrapper<U>)
{
static_assert(std::is_same<T,U>::value == false, "can't combine two of the same type");
return std::tuple<T, U> {};
}
...
using shouldFail2 = decltype(aaa | aaa);
// ^ now this correctly fails the static_assert in gcc 6.2
Run Code Online (Sandbox Code Playgroud)
我相信GCC和MSVC是正确的,但Clang是不正确的.所述static_assert
不应该火,因为根据标准在[temp.inst]/3:
除非已明确实例化或明确专门化了函数模板特化,否则在需要存在函数定义的上下文中引用特化时,将隐式实例化函数模板特化.
在未评估的上下文中decltype
,如果对未定义的函数进行调用是有效的,因此这不是需要存在函数定义的上下文.因此,static_assert
专业化主体中的声明不会被实例化.
归档时间: |
|
查看次数: |
413 次 |
最近记录: |