2

In this question I am led to a particular solution which involves partial specializations of templatized alias declarations. The generic case is described in this answer. Suppose I have a template class

template<typename T, ...>
class X {
    // ....
};

Rather than leaving T free and specializing the other template parameters I am in a situation in which the other arguments depend on T, and on T alone. As a very concrete example (more manageable than the example in the other question) consider a template class

template<typename T, T absVal(T)>
class Number_impl {
 private:
  T _t;
 public:
  Number_impl(T t): _t(t) {}
  T abs() const {return absVal(_t);}
};

Possible specializations are

 Number_impl<int, std::abs>;

and

Number_impl<double, std::fabs>;

(I know there are overloaded abs versions, this is just for the sake of illustration. See my other example if you want).

Ideally I would like to define a template class Number depending on a single argument, the type, so that Number<int> is equal to

Number_impl<int, std::abs>;

and Number<double> is equal to

Number_impl<double, std::fabs>;

Something like the following (which doesn't work):

template<typename T>
using Number = Number_impl<T, nullptr>;

template<>
using Number<int> = Number_impl<int, std::abs>;

template<>
using Number<double> = Number_impl<double, std::fabs>;

Does anyone know if and how this can be made to work, or how the same can be achieved in a different way?

Community
  • 1
  • 1
doetoe
  • 765
  • 7
  • 16
  • You can't specialize alias templates: see [here](http://stackoverflow.com/questions/7801228/can-i-specialize-a-class-template-with-an-alias-template), using `__Number` as a name is not a good idea - it's reserved see [here](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). On the topic - why don't you just use fftwpp which provides c++ wrappers for FFTW? – Rostislav Oct 13 '15 at 15:34
  • @Rostislav Thanks for the suggestion to have a look at FFTW++, I will. I am however still interested in this problem as a construction that can arise quite generally. I will change the name of __Number to Number_impl (like in the answer of Jarod42), I wasn't aware such names were reserved. – doetoe Oct 13 '15 at 16:21

2 Answers2

4

The normal way to do this kind of thing is the same way the standard library does it - with a traits class that you can specialise:

#include <iostream>
#include <cmath>

template<typename T> struct NumberTraits;

template<typename T, class Traits = NumberTraits<T>>
class Number {
private:
    T _t;
public:
    Number(T t): _t(t) {}
    T abs() const {
        return Traits::abs(_t);
    }
};

template<> struct NumberTraits<int>
{
    static int abs(int i) {
        return std::abs(i);
    }
};

template<> struct NumberTraits<double>
{
    static double abs(double i) {
        return std::fabs(i);
    }
};


using namespace std;

auto main() -> int
{
    Number<int> a(-6);
    Number<double> b(-8.4);
    cout << a.abs() << ", " << b.abs() << endl;
    return 0;
}

expected output:

6, 8.4
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
3

You may add a layer:

template<typename T, T absVal(T)>
class Number_impl {
private:
    T _t;
public:
    Number_impl(T t): _t(t) {}
    T abs() const {return absVal(_t);}
};

template<typename T> struct Number_helper;

template<> struct Number_helper<int>    { using type = Number_impl<int, std::abs>; };
template<> struct Number_helper<double> { using type = Number_impl<double, std::fabs>; };

template<typename T>
using Number = typename Number_helper<T>::type;
Jarod42
  • 203,559
  • 14
  • 181
  • 302