模板相关的假

时间:2018-07-25 16:45:55

标签: c++ c++11 templates language-lawyer

我有一个不能直接使用的类模板,只允许专业化。我想使用static_assert来显示有意义的错误消息。 我不能只键入static_assert(false, "error");,因为false不依赖于值,即使从未使用过模板,编译器也可能会显示错误消息。

我的解决方案:

template<class>
struct AlwaysFalse : std::false_type{};

#define DEPENDENT_FALSE(arg) AlwaysFalse<decltype(sizeof(arg))>::value

template<class T>
struct Foo{
    static_assert(DEPENDENT_FALSE(T), "You must use specialization!");
};

template<int i>
struct Bar{
    static_assert(DEPENDENT_FALSE(i), "You must use specialization!");
};

但是我不确定实现DEPENDENT_FALSE。因为MSVC doesn'tsizeof(arg)视为模板相关的表达式(unlike GCC),但是decltype(sizeof(arg)) is fine

有人可以用标准来解释这种行为吗?便携吗?

3 个答案:

答案 0 :(得分:4)

此:

#define DEPENDENT_FALSE(arg) AlwaysFalse<decltype(sizeof(arg))>::value

不能真正依赖 decltype(sizeof(arg))始终为size_t,它实际上不以任何方式依赖于arg(更广泛地说,这是一个list of expressions,从不依赖于类型)。由于不依赖,编译器完全能够看到DEPENDENT_FALSE(T)false并只需触发该static_assert

您想要的只是:

#define DEPENDENT_FALSE(arg) AlwaysFalse<decltype(arg)>::value

也就是说,放下sizeof。现在,这是依赖的。


这将不会直接对int起作用,因为它不再依赖于(decltype(i)只是int,现在我们需要依赖于值的东西)。为此,您可以将其包装在一个整数常量中:

template<class T>
struct Foo{
    static_assert(AlwaysFalse<T>::value, "You must use specialization!");
};

template<int i>
struct Bar{
    static_assert(AlwaysFalse<std::integral_constant<int, i>>::value, "You must use specialization!");
};

答案 1 :(得分:-1)

也许是以下想法:

template<typename T>
struct AlwaysError
{
    AlwaysError<T>()
    {
        std::cout << T::value << std::endl;
        static_assert( T::value, "You must use specialization!");
    }
};


template <typename T>
struct Foo: public AlwaysError<Foo<T>>
{
    static constexpr bool value = false;
};

template <>
struct Foo<int>{};

int main()
{
    //Foo<double> d; // error message as expected
    Foo<int> i;  // specialized, compiles!
}

assert消息包含文本和应专门化的类型。希望能有所帮助!

答案 2 :(得分:-1)

在C ++ 17上有效的解决方案。不幸的是我只有C ++ 11

template<auto>
constexpr bool dependentFalseHelper(){
    return false;
}
template<class>
constexpr bool dependentFalseHelper(){
    return false;
}

#define DEPENDENT_FALSE(arg) (dependentFalseHelper<arg>())