11

I have a class to describe some traits of a type.

template<typename T>
struct my_traits
{
    static constexpr int some_trait = 0;

    static constexpr T min() { return std::numeric_limtis<T>::min(); }
    static constexpr T max() { return std::numeric_limits<T>::max(); }
};

I want to specialize my_traits::some_trait but when I try:

template<> constexpr int my_traits<int>::some_trait = 1;

The compiler complains that my_traits::some_trait already has an initializer. Of course I can specialize it by doing:

template<>
struct my_traits<int>
{
    static constexpr int some_trait = 1;

    // min and max
};

but then I have to redefine all the other functions, even though they will be exactly the same.

So how can I specialize my_traits<int>::some_trait without having to repeat min and max?

maddisoj
  • 576
  • 6
  • 16
  • AFAIK this is not possible. A `constexpr` variable must be initialized or constructed in its declaration. – Daniel Jour Mar 13 '16 at 18:01
  • 6
    `static constexpr int some_trait = my_helper::value;` – Piotr Skotnicki Mar 13 '16 at 18:04
  • 1
    You could look to initialize it from a `constexpr` function, or utility class, that is specialized for the type `int` – Niall Mar 13 '16 at 18:04
  • Or if you can do without `constexpr` and use `const` instead, your code will work also. See [here](https://www.ibm.com/docs/en/i/7.1?topic=only-explicit-specialization-members-class-templates). – Mohammed Safwat Jul 04 '23 at 19:10

1 Answers1

10

There are several ways to do it. @Piotr Skotnicki and @Niall mentioned initializing through some helper that can be specialized. In general, just restructure your code so that you can specialize some classes or functions, and then use (by composition or inheritance) the specializing parts by parts which you don't need to specialize.

As an example of an alternative to the comments, here is a specializing base:

#include <iostream>                                                                                                                                                                                          
#include <limits>

template<typename T>
struct my_specializing_traits
{   
    static constexpr int some_trait = 0;
};  

template<>
struct my_specializing_traits<int>
{   
    static constexpr int some_trait = 1;
};  

Now you can just subclass it into a common part:

template<typename T>
struct my_traits :
    public my_specializing_traits<T>
{   
    static constexpr T min() { return std::numeric_limits<T>::min(); }
    static constexpr T max() { return std::numeric_limits<T>::max(); }
};  

The following shows it used (it outputs 0 and 1)

int main()
{   
    std::cout << my_traits<char>().some_trait << std::endl;
    std::cout << my_traits<int>().some_trait << std::endl;
}   
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185