Limiting Class Template Types
Asked Answered
A

2

5

I am attempting to use SFINAE to limit the allowable template parameter types for a class I am writing. Here is a simple contrived example I came up with that I believe illustrates what I would like to do.

I am sure this question is answered somewhere already, but I could not find it.

Here are two ways I have found to solve the problem:

First (SFINAE):

template <typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type>
class Integer {
public:
    T value;
};

int main() {
    Integer<int> i;             // Alowed
    Integer<double> d;          // Not allowed
    Integer<double, double> dd; // Allowed (Undesired)

    return 0;
}

What I don't like about this solution is that the third example in the main function works.

Second (static_assert):

#include <type_traits>

template <typename T>
class Integer {
    static_assert(std::is_same<T, int>::value, "T must be int");
public:
    T value;
};

int main() {
    Integer<int> i;    // Allowed
    Integer<double> d; // Not allowed

    return 0;
}

I think this solution is fine, but I was wondering if there is a more elegant or SFINAE way of accomplishing the same thing.

In this case, I would like to be able to enforce that the template type T must be integer for this simple example. Of course, in this case the class does not even need to be a template and I could just declare the type inside the Integer class to be of type int, but I want to use what I learn here in a more complex situation.

Antirachitic answered 23/5, 2019 at 16:22 Comment(2)
There will be concepts in C++20.Preposterous
I find the static_assert solution just fine: if a user of your class tries and use Integer<float>, they get a nice compilation error instead of an ugly sfinae-related wall of text.Prioress
D
5

You can fix you first example by using a unnamed non type template parameter. Changing it to

template <typename T, std::enable_if_t<std::is_same_v<T, int>, bool> = true>
class Integer {
public:
    T value;
};

will only allow Integer<int> i; to compile. It also stops users from trying to go around it using Integer<double, true> dd;

Downtrodden answered 23/5, 2019 at 16:26 Comment(0)
P
2

Use SFINAE the other (right) way:

template <typename T, typename std::enable_if<std::is_same<T, int>::value, int>::type = 0>
class Integer {
public:
    T value;
};

No more Hijack.

Preposterous answered 23/5, 2019 at 16:27 Comment(3)
Is there one too many closing angled bracket here? I'm not sure which one is extra.Antirachitic
@Pavis11: Typo fixed.Preposterous
You got your C++11 in the C++17 question!Selfpity

© 2022 - 2024 — McMap. All rights reserved.