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

时间:2017-03-20 20:41:05

标签: c++ c++14

我以为我理解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上工作。

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

1 个答案:

答案 0 :(得分:4)

.method public hidebysig instance float64 Abs() cil managed { // Code size 47 (0x2f) .maxstack 8 //000052: return Math.Sqrt(X * X + Y * Y + Z * Z); IL_0000: ldarg.0 IL_0001: call instance float64 CPUTests.Point3dProperties::get_X() IL_0006: ldarg.0 IL_0007: call instance float64 CPUTests.Point3dProperties::get_X() IL_000c: mul IL_000d: ldarg.0 IL_000e: call instance float64 CPUTests.Point3dProperties::get_Y() IL_0013: ldarg.0 IL_0014: call instance float64 CPUTests.Point3dProperties::get_Y() IL_0019: mul IL_001a: add IL_001b: ldarg.0 IL_001c: call instance float64 CPUTests.Point3dProperties::get_Z() IL_0021: ldarg.0 IL_0022: call instance float64 CPUTests.Point3dProperties::get_Z() IL_0027: mul IL_0028: add IL_0029: call float64 [mscorlib]System.Math::Sqrt(float64) IL_002e: ret } // end of method Point3dProperties::Abs .method public hidebysig specialname instance float64 get_X() cil managed { // Code size 7 (0x7) .maxstack 8 //000016: get { return _x; } IL_0000: ldarg.0 IL_0001: ldfld float64 CPUTests.Point3dProperties::_x IL_0006: ret } // end of method Point3dProperties::get_X 只是形象不对,因为它与[temp.res]发生冲突:

  

如果出现以下情况,该程序格式错误,无需诊断:
   - 无法为模板内的static_assert(false)语句(6.4.1)的模板或子语句生成有效的专业化,并且模板未实例化

您可以将其视为 - 因为constexpr if的常量表达式不依赖,编译器可以立即看到它的格式错误并触发。

您可以不为该专业化提供static_assert的定义,或者您可以执行以下操作:

fn()

即使没有人应该专门化template <class T> struct always_false : std::false_type { }; static_assert(always_false<some_dependent_type>::value, "..."); ,这也会使得生成有效的专业化成为可能。