【问题标题】:c++ template class pass constructor by ref depending on typec ++模板类根据类型通过ref传递构造函数
【发布时间】:2015-08-27 20:02:38
【问题描述】:

假设我有一个看起来像这样的类,如果 T 是像 double 这样的简单类型,则应按值构造,如果 T 更复杂,则应按引用构造。

到目前为止,我的代码如下所示:

template<class T>
class Val {
  public:
    Val() = default;
    Val(double v) : _v(v) {}

    template<typename U = T>
    Val(const &T v,
        typename std::enable_if<!std::is_same<U,double>::value, bool>::type = 0)
    : _v(v) {}
  private:
    T _v;
};

这很有效,但感觉很粗略,因为在构造函数中引入了一个额外的参数。这个问题有更好的解决方案吗?这似乎更适合重载或模板专业化解决方案?对于所有简单类型(intfloatdouble...),这是否可以普遍解决?

【问题讨论】:

  • 除非构造函数非常复杂以至于无法内联,否则我怀疑按值/引用传递对“简单类型”有影响。对我来说,这听起来确实是不必要的微优化。

标签: c++ templates parameter-passing metaprogramming sfinae


【解决方案1】:

你只需要一个构造函数。毕竟,它在两种情况下都做同样的事情对吗?首先,定义一个基于T 的类型特征,它可以是值也可以是引用:

template <typename T>
using param_type = std::conditional_t<
                       is_complex_type<T>::value,
                       T const&,
                       T>;

is_complex_type 是一些适当的类型特征,稍后将确定。也许它是is_fundamental 作为其他答案提出的。

然后就用它吧:

template<class T>
class Val {
public:
    Val() = default;
    Val(param_type<T> v) : _v(v) { }
};

【讨论】:

    【解决方案2】:

    std::is_fundamental 应该适合你。对我来说最好看的解决方案是:

    template<class T>
    typename std::enable_if< std::is_fundamental<T>::value >::type func(T p_arg){}
    
    template<class T>
    typename std::enable_if< !std::is_fundamental<T>::value >::type func(T const &p_arg){}
    

    【讨论】:

    • 但这不适用于构造函数,因为它们没有返回类型?
    • 这种情况下可以使用默认模板参数
    【解决方案3】:

    只需对您的代码稍作修改,再加上 Cyber​​Guy 推荐的 std::is_fundamental 即可满足您的需求。

    #include <iostream>
    using namespace std;
    
    template <class T>
    class Val
    {
    public:
        template <typename U = T>
        Val(T v,
            typename std::enable_if<std::is_fundamental<U>::value>::type* = 0)
            : _v(v)
        {
            cout << "fundamental" << endl;
        }
    
        template <typename U = T>
        Val(T const& v,
            typename std::enable_if<!std::is_fundamental<U>::value>::type* = 0)
            : _v(v)
        {
            cout << "complex" << endl;
        }
    
    private:
        T _v;
    };
    
    struct A {};
    
    int main()
    {
        Val<double> v1(1);
        Val<char> v2('a');
        Val<A> v3(A{});
    }
    

    输出:

    fundamental
    fundamental
    complex
    

    【讨论】:

    • 是的,一个或多个明确的更好的是使用默认模板参数
    【解决方案4】:

    您可以使用boost::call_traits&lt;T&gt;::param_type

    template<class T>
    class Val {
      public:
        Val() = default;
        Val(boost::call_traits<T>::param_type v) : _v(v) {}
      private:
        T _v;
    };
    

    【讨论】:

      猜你喜欢
      • 2018-07-06
      • 1970-01-01
      • 2018-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多