meguli
meguli

Reputation: 1526

Template specialization based on integer constant comparison

Here is something I have:

template <typename T, std::size_t dim>
struct vector;

template <std::size_t dim>
struct vector<float, dim>
{
    // I want this implementation for dim <= 4
}

template <std::size_t dim>
struct vector<float, dim>
{
    // I want this implementation for dim > 4
}

int main() {
    vector<float, 3> v1; // should instantiate first one
    vector<float, 7> v2; // should instantiate second one
}

Right now, this is not a working example of course, since I can't get it to work. I don't know how to arrange the specialization template signatures. They are same template arguments right now and won't compile. Somehow, a kind of SFINAE should enter the picture I guess but I am not allowed to have default template arguments on partial specializations.

I could use constexpr if to handle the code selection and have one specialization instead. But I believe, having seperate specializations for these makes things more readable and manageable.

How would you achieve this?

Upvotes: 2

Views: 574

Answers (3)

super
super

Reputation: 12928

You can achieve this by using SFINAE. You add an extra template parameter to the unspecialized template, then you make sure to match it in your specialization for a certain condition.

template <typename T, std::size_t dim, typename = void>
struct vector;

template <std::size_t dim>
struct vector<float, dim, std::enable_if_t<(dim <= 4)>>
{
    // I want this implementation for dim <= 4
};

template <std::size_t dim>
struct vector<float, dim, std::enable_if_t<(dim > 4)>>
{
    // I want this implementation for dim > 4
};

int main() {
    vector<float, 3> v1; // should instantiate first one
    vector<float, 7> v2; // should instantiate second one
}

std::enable_if_t will deduce to void by default if the condition passed to it is true. If not, it will not deduce to anything resulting in substitution failure leaving the way for any other template to match.

std::enable_if_t requires c++14 but you can use typename std::enable_if<condition>::type since c++11.

Upvotes: 7

bolov
bolov

Reputation: 75697

With concepts you can simply write:

template <typename T, std::size_t dim>
struct vector;

template <std::size_t dim>
    requires (dim <= 4)
struct vector<float, dim>
{
    // I want this implementation for dim <= 4
};

template <std::size_t dim>
    requires (dim > 4)
struct vector<float, dim>
{
    // I want this implementation for dim > 4
};

See it on godbolt

We just have to wait for them

Upvotes: 1

Dmytro Dadyka
Dmytro Dadyka

Reputation: 2250

Possible solution using additional layer. We use additional bool template argument and specialization for this arg. Can be used for version less than С++11.

template <typename T, std::size_t dim, bool moreThanFour>
struct vectorImpl;

template <std::size_t dim>
struct vectorImpl<float, dim, false>
{
   // I want this implementation for dim <= 4
};

template <std::size_t dim>
struct vectorImpl<float, dim, true>
{
   // I want this implementation for dim > 4
};

template <typename T, std::size_t dim>
struct vector : public vectorImpl < T, dim, (dim > 4) > {};

int main() {
   vector<float, 3> v1; // should instantiate first one
   vector<float, 7> v2; // should instantiate second one
}

Upvotes: 3

Related Questions