2014-10-19 54 views
3

我想提供兩個版本的相同模板函數,一個用於任何可以像tuple那樣操作的東西,即與tuple_sizestd::get一起使用的東西。我不在乎它是否得到std::array s,只要它得到元組和對。編寫通用版本沒有問題,但我似乎無法使類似元組的版本繼續存在。對於元組類型(元組,對)模板過載

// 1 
template <typename T> 
A func(T&& t) { /* ... */ } 

// 2 
template <typename TupleType, 
      std::size_t Size=std::tuple_size<std::decay_t<TupleType>>::value> 
B func(TupleType&& tup) { /* ... */ } 

與實例:

int main() { 
    int i; 
    std::vector<int> v; 
    auto t = std::make_tuple(1, 2.0, 'a'); 
    auto p = std::make_tuple(1, 2.0); 

    A a = func(i); // calls 1 
    a = func(v); // calls 1 

    B b = func(t); // ambiguous, should call 2 
    b = func(p); // ambiguous, should call 2 
} 

我知道我可以寫一個元組的幾個重載,但是這是一個很大的寫作,並會在pair的情況下產生的中間。我不想失去對原始對的引用,因爲這只是一個轉發功能。

template <typename... Ts> 
B func(std::tuple<Ts...>& tup) { } 

template <typename... Ts> 
B func(const std::tuple<Ts...>& tup) { } 

template <typename... Ts> 
B func(std::tuple<Ts...>&& tup) { } 

反正我有可以使main工作的方式我想上面的電話,用一個通用轉發功能?

更新:這些功能的返回類型不同。應該包括那首先,我簡化。

回答

6
template <typename T, typename U = void> 
struct is_tuple_like : std::false_type {}; 

template <typename T> 
struct is_tuple_like<T, decltype((void)std::get<0>(std::declval<T>()), (void)std::tuple_size<T>::value)> : std::true_type {}; 

template <typename T, std::enable_if_t<!is_tuple_like<std::decay_t<T>>{}, int> = 0> 
A func(T&& t) 
{ 
    return {}; 
} 

template <typename TupleType, std::enable_if_t<is_tuple_like<std::decay_t<TupleType>>{}, int> = 0> 
B func(TupleType&& tup) 
{ 
    return {}; 
} 

DEMO


與標籤調度的替代解決方案:

template <typename T> 
A _func(T&& t, std::false_type) 
{ 
    return {}; 
} 

template <typename TupleType> 
B _func(TupleType&& tup, std::true_type) 
{ 
    return {}; 
} 

template <typename TupleOrNot> 
auto func(TupleOrNot&& t) 
{ 
    return _func(std::forward<TupleOrNot>(t), is_tuple_like<std::decay_t<TupleOrNot>>{}); 
} 

DEMO 2

+4

1,但標籤調度將比SFINAE是清潔器。 – Yakk 2014-10-19 19:06:13

2

使第二個函數模板一個更好的匹配,如果它的工作原理:

// 1 
template <typename T> 
void func_(T&& t, long) { /* ... */ } 

// 2 
template <typename TupleType, 
      std::size_t Size=std::tuple_size<std::decay_t<TupleType>>::value> 
void func_(TupleType&& tup, int) { /* ... */ } 

template <typename T> 
void func(T&& t) { func_(std::forward<T>(t), 0); } 

Demo。 這個概念可以概括 - 來自Xeo的this article解釋得非常好。