元组类型的模板重载(元组,对)

时间:2014-10-19 18:37:45

标签: c++ templates c++14

我正在尝试提供相同模板化函数的两个版本,一个用于可以像tuple一样工作的任何版本,即适用于tuple_sizestd::get的内容。我不在乎它是否得到std::array,只要它得到元组和对。编写通用版本没有问题,但我似乎无法让类似元组的版本坚持下去。

// 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的方式按照我想要的方式进行上述调用吗?

更新:这些功能的返回类型不同。应该首先包括,我过于简单了。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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很好地解释了它。