fuji
fuji

Reputation: 1203

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...)?

Upvotes: 3

Views: 190

Answers (4)

Jarod42
Jarod42

Reputation: 218098

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

Upvotes: 1

Barry
Barry

Reputation: 303537

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

Upvotes: 6

LogicStuff
LogicStuff

Reputation: 19617

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

Upvotes: 2

CyberGuy
CyberGuy

Reputation: 2813

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

Upvotes: 4

Related Questions