简体   繁体   中英

c++ template class pass constructor by ref depending on type

Let's say I have a class which looks like this which should either be constructed by value if T is a simple type like double or by reference if T is more complex.

The code I have so far looks like this:

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

Which works, but feels really sketchy, since an additional parameter is introduced into the constructor. Is there a better solution to this problem? It seems like this would be better suited for an overload or template specialization solution? Can this be solved generally for all simple types ( int , float , double ...)?

You only need to have one constructor. It, after all, does the same thing in both cases right? First, define a type trait which, based on T , is either a value or reference:

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

Where is_complex_type is some appropriate type trait to be determined later. Maybe it's is_fundamental as other answers proposed.

And then just use it:

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

There is std::is_fundamental which should fit you. Best looking solution for me is:

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){}

Just a little modified version of your code along with CyberGuy's recommendation of std::is_fundamental will do what you want.

#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{});
}

Output:

fundamental
fundamental
complex

You may use boost::call_traits<T>::param_type

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM