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?
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;
}
Related
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?
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;
}
I have a templated class for which I would like to provide a constexpr integer whose value is determined by the presence or absence of a constexpr integer in the template parameter:
template<typename Traits>
class Foo
{
static constexpr int MaxDegree =
std::conditional<
std::is_integral<Traits::MaxDegree>::value,
std::integral_constant<int, Traits::MaxDegree>,
std::integral_constant<int, 0>
>::value;
};
struct TraitA { };
struct TraitB { constexpr static int MaxDegree = 1; };
int main()
{
std::cout
<< Foo<TraitA>::MaxDegree /* should be 0 */ << " "
<< Foo<TraitB>::MaxDegree; /* should be TraitB::MaxDegree == 1 */
<< "\n";
}
Obviously, this doesn't work since std::is_integral fails for TraitA. Is there anything that will work?
I'm constrained to c++11.
Traits::MaxDegree
yields a compiler error, if the member doesn't exist. This means you cannot use this code as part of the expression directly.
You could use constexpr functions with SFINAE to implement this though:
template<class T>
constexpr typename std::enable_if<std::is_integral<decltype(T::MaxDegree)>::value, int>::type GetMaxDegree()
{
return T::MaxDegree;
}
template<class T>
constexpr int GetMaxDegree(...) // this one is only used, if the first version results in a substitution failure
{
return 0;
}
template<typename Traits>
class Foo
{
public:
static constexpr int MaxDegree = GetMaxDegree<Traits>();
};
I'd like to be able to specify default non-type template parameter by calling one of overloaded fuctions (that are template with full specialization). Following code represents the problem: I expecet FieldType2 getDefaultField<FieldType2>() to be printed, but Called getDefaultField() ! is printed.
#include <iostream>
enum class FieldType1 {
Description1,
Description2,
Description3
};
enum class FieldType2 {
Description1,
Description2,
Description3
};
template<class FiledType>
struct FieldDescription {
constexpr static int startPos{0};
constexpr static FieldType fieldType{};
};
struct ConcreteField2 : public FieldDescription<FieldType2> {};
template<class FieldType>
constexpr FieldType getDefaultField() {
return FieldType{};
};
template<>
constexpr FieldType1 getDefaultField<FieldType1>() {
return FieldType1::Description1;
};
template<>
constexpr FieldType2 getDefaultField<FieldType2>() {
return FieldType2::Description3;
};
template<class FieldDescr,
decltype(FieldDescr::fieldType) fieldType = getDefaultField<decltype(FieldDescr::fieldType)>()>
void process() {
if (fieldType == FieldType2::Description3) {
std::cout << "FieldType2 getDefaultField<FieldType2>()" << std::endl;
}
if (fieldType == FieldType2::Description1) {
std::cout << "Called getDefaultField() !" << std::endl;
}
}
int main() {
process<ConcreteField2>();
return 0;
}
decltype(FieldDescr::fieldType) is const FieldType2 not FieldType2. So your specialisation doesn't match and primary template is used.
You might use std::decay_t:
getDefaultField<std::decay_t<decltype(FieldDescr::fieldType)>>()
Demo
But as suggested in comment, that usage of dummy member is strange, a regular using type = FiledType; is more idiomatic.
I'd suggest don't use decltype and decay_t and use using to alias FieldType instead:
template<class FT>
struct FieldDescription {
using FieldType = FT;
constexpr static int startPos{0};
// constexpr static FieldType fieldType{}; // You can get rid of that member,
// unless used elsewhere
};
and
template <class FieldDescr,
typename FieldDescr::FieldType fieldType =
getDefaultField<typename FieldDescr::FieldType>()>
I need to define a class, foo, with a static member variable template, foo::static_variable_template<T>. This member should only exist when T fulfills certain requirements. For example, when the constexpr static function T::constexpr_static_function() exists. Otherwise, foo::static_variable_template<T> should not exist. Moreover, I would like to be able to test for the existence of foo::static_variable_template<T> at compile-time via SFINAE.
Here is an approximation of what I would like to do:
#include <iostream>
struct foo
{
template<class T>
static constexpr int static_variable_template =
T::constexpr_static_function();
// XXX this works but requires a second defaulted template parameter
// template<class T, int = T::constexpr_static_function()>
// static constexpr int static_variable_template =
// T::constexpr_static_function();
};
struct has_constexpr_static_function
{
static constexpr int constexpr_static_function() { return 42; }
};
struct hasnt_constexpr_static_function
{
};
template<class T, class U,
int = T::template static_variable_template<U>>
void test_for_static_variable_template(int)
{
std::cout << "yes it has\n";
}
template<class T, class U>
void test_for_static_variable_template(...)
{
std::cout << "no it hasn't\n";
}
int main()
{
test_for_static_variable_template<foo, has_constexpr_static_function>(0);
test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}
This approximation nearly works, but only if foo::static_variable_template has a second, defaulted template parameter. Because this second parameter is an implementation detail, I'd like to hide it from the public interface of foo::static_variable_template.
Is this possible in C++17?
I am not sure if your intent is to initialise foo::static_variable_template with 0 if T::constexpr_static_function() is missing or you want to disable it entirely. In case of the former, this might be useful. For example, this (clunky) solution works (requires C++17 for if constexpr; note that your variable is now a function):
#include <iostream>
template <typename T>
class has_func
{
typedef char does;
typedef long doesnt;
template <typename C> static does test( decltype(&C::constexpr_static_function) );
template <typename C> static doesnt test(...);
public:
static constexpr bool value()
{
return sizeof(test<T>(0)) == sizeof(char);
}
};
struct foo
{
template<class T>
static constexpr int static_variable_template()
{
if constexpr (has_func<T>::value())
{
return T::constexpr_static_function();
}
return 0;
}
// XXX this works but requires a second defaulted template parameter
// template<class T, int = T::constexpr_static_function()>
// static constexpr int static_variable_template =
// T::constexpr_static_function();
};
struct has_constexpr_static_function
{
static constexpr int constexpr_static_function() { return 42; }
};
struct hasnt_constexpr_static_function
{
};
template<class T, class U>
void test_for_static_variable_template(...)
{
if constexpr (has_func<U>::value())
{
std::cout << "yes it has\n";
}
else
{
std::cout << "no it hasn't\n";
}
}
int main()
{
std::cout << foo::static_variable_template<has_constexpr_static_function>() << "\n";
std::cout << foo::static_variable_template<hasnt_constexpr_static_function>() << "\n";
/// Original test
test_for_static_variable_template<foo, has_constexpr_static_function>(0);
test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}
Prints
42
0
yes it has
no it hasn't
Tested with clang 5.0.1.
In case you want to disable foo::static_variable_template entirely, you might need to use std::enable_if:
#include <iostream>
template <typename T>
class has_func
{
typedef char does;
typedef long doesnt;
template <typename C> static does test( decltype(&C::constexpr_static_function) );
template <typename C> static doesnt test(...);
public:
static constexpr bool value()
{
return sizeof(test<T>(0)) == sizeof(char);
}
};
struct foo
{
template<class T, typename std::enable_if<has_func<T>::value()>::type ...>
static constexpr int static_variable_template()
{
if constexpr (has_func<T>::value())
{
return T::constexpr_static_function();
}
return 0;
}
// XXX this works but requires a second defaulted template parameter
// template<class T, int = T::constexpr_static_function()>
// static constexpr int static_variable_template =
// T::constexpr_static_function();
};
struct has_constexpr_static_function
{
static constexpr int constexpr_static_function() { return 42; }
};
struct hasnt_constexpr_static_function
{
};
template<class T, class U>
void test_for_static_variable_template(...)
{
if constexpr (has_func<U>::value())
{
std::cout << "yes it has\n";
}
else
{
std::cout << "no it hasn't\n";
}
}
int main()
{
std::cout << foo::static_variable_template<has_constexpr_static_function>() << "\n";
// We can't print this because it doesn't exist.
// std::cout << foo::static_variable_template<hasnt_constexpr_static_function>() << "\n";
/// Original test
test_for_static_variable_template<foo, has_constexpr_static_function>(0);
test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}
In this line of thought, I am not sure if you can disable a static template variable with std::enable_if. To quote the great Riemann, "I have for the time being, after some fleeting vain attempts, provisionally put aside the search for this..."
The following will compile with GCC 5.2 but not with Visual Studio 2015.
template <typename Derived>
struct CRTP {
static constexpr int num = Derived::value + 1;
};
struct A : CRTP<A> {
static constexpr int value = 5;
};
It complains that A does not have a member named value.
How to fix the code so that it compiles on both compilers? Or is it illegal altogether?
Try making it a constexpr function instead. The way you have it setup now attempts to access an incomplete type.
Since a templated member function will only be initialized upon first being used, type A will be fully defined by that point.
#include <iostream>
template <typename Derived>
struct CRTP {
static constexpr int num() { return Derived::value + 1; }
};
struct A : CRTP<A> {
static constexpr int value = 5;
};
int main()
{
std::cout << A::num();
return 0;
}
See it live here
The problem is here:
template <typename Derived>
struct CRTP {
static constexpr int num = Derived::value + 1;
↑↑↑↑↑↑↑↑↑
};
At the time of the instantiation of CRTP<A>, A isn't a complete class yet, so you can't actually access static members of it.
One workaround is to pass in num as a separate template argument:
template <typename Derived, int N>
struct CRTP {
static constexpr int num = N;
};
struct A : CRTP<A, 5> {
};