c++ - 通过 decltype 表达式调用时 static_assert 是否应该工作?

标签 c++ c++11 decltype static-assert

我预计以下代码会因最后一行的 static_assert 检查而失败。但是在 MSVC2015 和 gcc 6.2 中,它编译成功。它确实无法按预期在 clang 3.9 中进行编译。这是编译器错误还是 static_assertdecltype() 中不起作用?

#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

更新 #1:附加问题

Brian 建议 static_assert 不会在 decltype 上下文中触发,因为该值尚未明确实例化。所以我在下面添加了一个额外的测试来显式实例化 shouldFail2 类型 ,我认为按照 Brian 的逻辑应该会导致 static_assert 失败。 但是,下面的代码在 MSVC2015 或 gcc 6.2 中不会失败。 这是一个错误,还是我忽略了什么? 编辑:似乎一旦 decltype 提取了类型,我们就可以自由使用 shouldFail2 无需进一步引用 operator| 的定义。

shouldFail2 shouldFail3 = {}; // instantiate shouldFail2.
// ^ doesn't fail in MSVC2015 or gcc 6.2.

更新#2

如果我将 operator| 的定义更改为使用没有尾随返回类型的 auto(或 decltype(auto)),那么decltype 表达式正确地使 gcc 6.2 中的 static_assert 失败。但是,此版本无法在 MSVC2015 中编译(错误 C3779、C2088)。编辑:作为 W.F.下面指出,省略尾随返回类型是 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

最佳答案

我相信 GCC 和 MSVC 是正确的,而 Clang 是不正确的。 static_assert 不应触发,因为根据 [temp.inst]/3 的标准:

Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist.

在未计算的上下文中,例如 decltype,调用未定义的函数是有效的,因此这不是要求函数定义存在的上下文。因此,特化主体中的 static_assert 声明未实例化。

关于c++ - 通过 decltype 表达式调用时 static_assert 是否应该工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41010924/

相关文章:

c++ - 类 std::vector 没有名为的成员

c++ - C++十进制类型和括号-为什么?

使用 decltype 和 constness 的 C++11 尾随返回成员函数

c++ - 在 decltype 中使用命名空间

c++ - QList<QString> 运算符<<

c++ - 自动检测不正确的 find_first_of() 和 family 情况的方法

python - 使用多线程和 OpenCV imshow() 同时显示多个图像流

c++ - C++/C 中是否有任何有效的构建函数可以快速均匀地采样 b 个条目而不用替换 n 个条目?

c++ - 数组元素打印的递归方法

c++ - 使用 vector<char> 作为缓冲区而不在 resize() 上初始化它