2017-03-20 81 views
1

我以爲我明白static_assert是如何工作的。但是,當我想這對G ++編譯器,我開始懷疑:如果未實例化成員模板,是否要評估static_asserts?

#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)和鐺(3.9.1),但工作在VC++ 2015

這是一個缺陷還是我失去了一些東西?

回答

4

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