【问题标题】:How to implement optional template parameters?如何实现可选模板参数?
【发布时间】:2012-05-22 21:05:11
【问题描述】:

如何实现可选模板参数?

我想要一个类MyStruct<T1,T2,T3>,它只允许使用第一个或前两个参数。现在,处理MyStruct<T1,T2,T3> 的函数也应该以某种方式正确处理未使用的模板参数。

例子:

#include <iostream>

template<class T1, class T2, class T3>
struct MyStruct {
  T1 t1; T2 t2; T3 t3;
  MyStruct() {}
  MyStruct(T1 const& t1_, T2 const& t2_, T3 const& t3_)
    : t1(t1_), t2(t2_), t3(t3_) {}
};

template<class T1, class T2, class T3>
MyStruct<T1, T2, T3> myplus(MyStruct<T1, T2, T3> const& x,
                MyStruct<T1, T2, T3> const& y) {
  return MyStruct<T1, T2, T3>(x.t1 + y.t1, x.t2 + y.t2, x.t3 + y.t3);
}

int main() {
  typedef MyStruct<int, double, std::string> Struct;
  Struct x(2, 5.6, "bar");
  Struct y(6, 4.1, "foo");
  Struct result = myplus(x, y);
  // (8, 9.7, "barfoo")
  std::cout << result.t1 << "," << result.t2 << "," << result.t3;
}

现在我想更改代码,使上面的main() 函数仍然有效,但以下也可以:

typedef MyStruct<std::string, int> Struct;
// result: ("barfoo", 5)
Struct result = myplus(Struct("bar", 2), Struct("foo", 3));

或者这个:

typedef MyStruct<int> Struct;
// result: (5)
Struct result = myplus(Struct(2), Struct(3));

我认为boost::tuple 使用了类似的技巧,您可以使用boost::tuple&lt;A&gt;boost::tuple&lt;A,B&gt;boost::tuple&lt;A,B,C&gt;,但我不确定他们是如何做到的。

【问题讨论】:

    标签: c++ templates boost


    【解决方案1】:

    如果我理解正确,您应该能够为您的模板传递默认参数:

    template<class T1, class T2 = Default, class T3 = Default>
    

    您可以用任何类型替换Default

    【讨论】:

    • 我明白了,如果我定义一个返回简单 Default()operator+(Default const&amp; Default const&amp;)plus() 函数将起作用。不错。
    【解决方案2】:

    您可以在 C++11 中使用可变参数模板来执行此操作(更难且更复杂的选项);或者,您可以使用默认模板参数,如 Boost.Tuple:

    // boost/tuple/tuple/detail/tuple_basic.hpp
    
    // -- null_type --------------------------------------------------------
    struct null_type {};
    
    //...
    
    // - tuple forward declaration -----------------------------------------------
    template <
      class T0 = null_type, class T1 = null_type, class T2 = null_type,
      class T3 = null_type, class T4 = null_type, class T5 = null_type,
      class T6 = null_type, class T7 = null_type, class T8 = null_type,
      class T9 = null_type>
    class tuple;
    

    【讨论】:

    • 请注意,正如 boost 文档所说的 The current version supports tuples with 0-10 elements.。所以这里没有太多的魔法。只是使用默认值的硬编码上限。
    【解决方案3】:

    你可以故意做一个“未使用”的类型:

    namespace detail { struct unused { }; }
    
    template <typename T1, typename T2 = detail::unused, typename T3 = detai::unused>
    struct MyStruct
    {
        typedef T1 type1;
        typedef T2 type2;
        typedef T3 type3;
    
        explicit MyStruct(type1 const & t1,
                          type2 const & t2 = type2(),
                          type3 const & t3 = type3())
        : x1(t1), x2(t2), x3(t3)
        {  }
    
    private:
        type1 x1;
        type2 x2;
        type3 x3;
    };
    

    【讨论】:

    • 我不认为将Unused放在匿名命名空间中是个好主意——如果将MyStruct放在标题中,不同的翻译单元会得到不同的Unuseds,导致不同的MyStructs 并违反了 ODR。
    猜你喜欢
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多