Template dependent false

时光总嘲笑我的痴心妄想 提交于 2020-01-23 14:27:07

问题


I have a class template which can't be used directly, only specializations are allowed. And I want to use static_assert to show meaningful error message. I can't just type static_assert(false, "error"); since false isn't value dependent and compiler may show error message even if the template is never used.

My solution:

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!");
};

But I'm not sure about realization DEPENDENT_FALSE. Because MSVC doesn't treat sizeof(arg) as template dependent expression(unlike GCC), but decltype(sizeof(arg)) is fine.

Can somebody explain this behavior in terms of standard? Is it portable?


回答1:


This:

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

fails to actually be dependent. decltype(sizeof(arg)) is always size_t, it doesn't actually depend on arg in any way (more broadly, here is a list of expressions that are never type-dependent). Since it's not dependent, a compiler is perfectly able to see that DEPENDENT_FALSE(T) is false and just trigger that static_assert.

What you want is just:

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

That is, drop the sizeof. This now is dependent.


This won't work for the int directly, since that again won't be dependent (decltype(i) is just int, and we need something value-dependent now). For that, you can just wrap it in an integral constant:

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!");
};



回答2:


Maybe the following idea:

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!
}

The assert message contains the text and also the type which should be specialized. In hope it helps!




回答3:


Solution which works on C++17. Unfortunately I have only C++11

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

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


来源:https://stackoverflow.com/questions/51523965/template-dependent-false

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!