如果未实例化成员模板,是否要评估static_asserts?

Are static_asserts to be evaluated if a member template isn't instantiated?

本文关键字:评估 static asserts 是否 实例化 成员 如果      更新时间:2023-10-16

我想我理解了static_assert是如何工作的。 但是当我在 g++ 编译器上尝试这个时,我开始怀疑:

#include <iostream>
#include <type_traits>
#define ENABLE_IF(...) std::enable_if_t<__VA_ARGS__, int> = 0
template<typename...Ts>
struct list{};
template<typename...Ts>
struct is_one_of;
template<template <typename...> class TT, typename T, typename T1, typename...Ts>
struct is_one_of<T, TT<T1, Ts...>> : is_one_of<T, TT<Ts...>> {};
template<template <typename...> class TT, typename T, typename...Ts>
struct is_one_of<T, TT<T, Ts...>> : std::true_type {};
template<template <typename...> class TT, typename T>
struct is_one_of<T, TT<>> : std::false_type {};

template<typename...Ts>
struct X;
template<typename P, typename T, typename...Ts>
struct X<P, T, Ts...> : X<P, Ts...>
{
  using X<P, Ts...>::fn;
  template<typename R, ENABLE_IF(std::is_same<T, R>::value)>
  constexpr auto fn(R&& x)
  {
    return x;
  }
};
template<template <typename...> class TT, typename...Ts>
struct X<TT<Ts...>>
{
  template<typename R, ENABLE_IF(!is_one_of<R, TT<Ts...>>::value)>
  constexpr auto fn(R&& x)
  {
    static_assert(false, "Type R didn't match");
  }
};

template<typename...Ts>
struct XX : X<list<Ts...>, Ts...> {};

int main() {
    XX<int, float> x;
    std::cout << x.fn(int(3)) << std::endl;
    return 0;
}

现在我会认为基类型X<TT<Ts...>>不可能被实例化,因为它永远不会被调用。 通过这种推理,它不应该导致static_assert失败。

这在 g++ (5.4.0( 和 clang (3.9.1( 上失败,但在 VC++ 2015 上有效。

这是缺陷还是我错过了什么?

编写static_assert(false)只是格式不正确,因为它与 [temp.res] 相冲突:

程序格式不正确,无需诊断,如果:
— 无法为模板或模板内 constexpr if 语句 (6.4.1( 的子语句生成有效的专用化,并且模板未实例化

你可以把它想象成 - 因为static_assert的常量表达式不是依赖的,编译器可以立即看到它的格式不正确和火灾。

<小时 />

您可以不为该专业化提供fn()的定义,也可以执行以下操作:

template <class T> struct always_false : std::false_type { };
static_assert(always_false<some_dependent_type>::value, "...");

这将使假设有可能产生有效的专业化,即使没有人应该专门化always_false