当通过声明表达式调用时,static_assert应该可以工作

Is static_assert supposed to work when invoked via decltype expression?

本文关键字:assert 工作 static 声明 表达式 调用      更新时间:2023-10-16

我希望以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 Type ,我认为Brian的逻辑应导致static_assert失败。,下面的代码在MSVC2015或GCC 6.2中不会失败。这是一个错误,还是我忽略了某些内容? edit:看来,一旦decltype提取了类型,我们就可以免费使用shouldFail2,而无需进一步参考operator|的定义。

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

更新#2

如果我将operator|的定义更改为使用auto(或decltype(auto))而没有落后返回类型,则decltype表达式正确使static_assert在GCC 6.2中失败。但是,此版本未能在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的标准:

除非已明确实例化或明确专业化函数模板专业化,否则当在上下文中引用专业化时,函数模板专业化将暗中实例化 需要一个函数定义。

在诸如decltype之类的未评估上下文中,请呼叫未定义的函数,因此这不是需要存在函数定义的上下文。因此,未实例化专业主体中的static_assert声明。