【问题标题】:template overload for tuple-like types (tuple, pair)类元组类型的模板重载(元组,对)
【发布时间】:2015-06-28 04:36:59
【问题描述】:

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

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

我知道我可以为 tuple 编写一些重载,但编写的内容很多,并且会在 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 中进行上述调用吗?

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

【问题讨论】:

    标签: c++ templates c++14


    【解决方案1】:
    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,但标签调度会比 SFINAE 更干净。
    【解决方案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 很好地解释了它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-16
      • 1970-01-01
      • 2023-04-01
      • 2021-03-27
      • 1970-01-01
      • 1970-01-01
      • 2021-07-26
      相关资源
      最近更新 更多