2015-10-13 110 views
2

在我的例子中,我有一個類Foo<T>。在我的函數test中,我需要獲取Foo的模板參數,否則爲正常類型。首先,我開始使用std::conditional,但忘記模板參數必須全部有效,無論選擇哪一個。是爲non-Foo類型創建類型專業化的唯一方法嗎?訪問類型成員

Example

#include <type_traits> 

template <typename TYPE> 
class Foo 
{ 
public: 
    using M = TYPE; 
}; 

template <typename T> 
void test(const T& a) 
{ 
    // actually I would have used !is_foo<T>::value for the first arg 
    // but this check is fine to minimise the example 
    using MY_TYPE = typename std::conditional< 
    std::is_same<T, int>::value, 
    T, 
    typename T::M>::type; // <---Error: error: type 'int' cannot be used prior to '::' because it has no members 
} 

int main() 
{ 
    test(Foo<int>()); // MY_TYPE must be int 
    test(int()); // MY_TYPE must be int 
    return 0; 
} 

回答

5

那麼你可以做一個UnFoo幫手得到正確的類型爲您提供:

template <typename T> 
struct UnFoo { 
    using type = T; 
}; 

template <typename T> 
struct UnFoo<Foo<T>> { 
    using type = T; 
}; 

template <typename T> 
void test(const T& a) 
{ 
    using MY_TYPE = typename UnFoo<T>::type; //maybe with a helper to get rid of typename 
} 

另一種選擇是寫一個Foo<T>過載,並把它委託給其他功能,但這取決於你真正的test功能。

0
#include <type_traits> 

template <typename TYPE> 
class Foo 
{ 
public: 
    using M = TYPE; 
}; 

template <typename T> 
void test(const Foo<T>& a) 
{ 
    using MY_TYPE = Foo<T>::M; 
    testOther<MY_TYPE>(a); 
} 

template <typename T> 
void test(const T& a) 
{ 
    using MY_TYPE = T; 
    testOther<MY_TYPE>(a); 
} 

template <typename T, typename S> 
void testOther(const S& a) 
{ 
    // do stuff 
} 

int main() 
{ 
    test(Foo<int>()); // MY_TYPE must be int 
    test(int()); // MY_TYPE must be int 
    return 0; 
} 

我不完全確定你想要什麼,但我希望這是你想要的。它可能有點偏離。我沒有編譯這個。

2

你可以做一些void_t魔力,讓SFINAE給你看着辦助陣:

#include <type_traits> 
#include <iostream> 
#include <typeinfo> 

template <typename TYPE> 
class Foo 
{ 
public: 
    using M = TYPE; 
}; 

template<typename... Ts> struct make_void { typedef void type;}; 
template<typename... Ts> using void_t = typename make_void<Ts...>::type; 

// primary template handles types that have no nested ::T member: 
template< class T, class = void_t<> > 
struct M_or_T { using type = T; }; 

// specialization recognizes types that do have a nested ::T member: 
template< class T > 
struct M_or_T<T, void_t<typename T::M>> { using type = typename T::M; }; 


template <typename T> 
void test(const T& a) 
{ 
    using MY_TYPE = typename M_or_T<T>::type; 
    std::cout << typeid(MY_TYPE).name() << "\n"; 
} 

int main() 
{ 
    test(Foo<int>()); // MY_TYPE must be int 
    test(int()); // MY_TYPE must be int 
    return 0; 
} 

什麼情況是,M_or_T替代的第二重載int失敗(以及任何類型的無類型成員M)並因此選擇第一超載。對於類型成員爲M的類型,選擇更專門化的第二個過載。

+0

我認爲使用SFINAE和'void_t'對此有點矯枉過正。 – TartanLlama

+3

@TartanLlama也許。然而,在學習TMP(我感覺OP在做)的時候,學習'void_t'並不會讓人感到痛苦。 – Rostislav