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
?
A non-static data member cannot be constexpr. static constexpr int x = 5; int y; };
static defines the object's lifetime during execution; constexpr specifies that the object should be available during compilation. Compilation and execution are disjoint and discontiguous, both in time and space. So once the program is compiled, constexpr is no longer relevant.
constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.
#define directives create macro substitution, while constexpr variables are special type of variables. They literally have nothing in common beside the fact that before constexpr (or even const ) variables were available, macros were sometimes used when currently constexpr variable can be used.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With