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> {
};
Related
I'm trying to understand the reason for the compilation error with my CRTP implementation in this example:
template<class T>
struct Interface
{
static constexpr int func();
static constexpr int func2();
};
template<class T>
struct Default : public Interface<T>
{
constexpr static int impl_func()
{
return 0;
}
constexpr static int impl_func2()
{
return Default<T>::func() + 2; <----------- (A)
}
};
struct Derived : public Default<Derived>
{
static constexpr int impl_func2()
{
// NOTE: Using impl_func instead of func here compiles
return func() + 4; <-------------- (B)
}
};
struct Derived2 : public Default<Derived2>
{
};
template <typename T> constexpr int Interface<T>::func()
{
return T::impl_func();
}
template <typename T> constexpr int Interface<T>::func2()
{
return T::impl_func2();
}
int main()
{
constexpr int ret = Derived::func2();
static_assert(ret == 4);
constexpr int ret2 = Derived2::func2();
static_assert(ret2 == 2);
}
Specifically why is (A) ok while (B) gives me this error:
test3.cpp:45:19: error: constexpr variable 'ret' must be initialized by a constant expression
constexpr int ret = Derived::func2();
^ ~~~~~~~~~~~~~~~~
test3.cpp:29:16: note: undefined function 'func' cannot be used in a constant expression
return func() + 4;
Replacing (B) with return impl_func() + 4 compiles successfully. But neither Derived::func() nor Default<Derived>::func() work. If (B) needs to be impl_func() then is there something different about the fact that (A) is in a templated class that allows it to compile successfully?
With constexpr function, definition should be available when used...
reordering function definition solve the issue:
template<class T>
struct Interface
{
static constexpr int func();
static constexpr int func2();
};
template <typename T> constexpr int Interface<T>::func()
{
return T::impl_func();
}
template <typename T> constexpr int Interface<T>::func2()
{
return T::impl_func2();
}
// Remaining code.
Demo
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 this code which I wasn't able to compile and I was wondering if there's a way around it. Error is - Argument list for class template "a" is missing.
//not compiling one
template <typename T = int>
struct a {
static T x;
static T function(T number) {
return x = number;
}
};
template <typename T>
T a<T>::x;
int main() {
int b = a::function(5);
return 0;
}
.
//compiling one
template <typename T = int>
struct a {
static T x;
static T function(T number) {
return x = number;
}
};
template <typename T>
T a<T>::x;
int main() {
int b = a<int>::function(5);
return 0;
}
Why can it not use the template argument we passed on default and how can we fix that without entering the template parameter?
The default template parameter int can be used without specifying it, you just need to specify that a is a template:
int b = a<>::function(5);
// ^^
is there a way to do without a<>, just a?
In case your class template a is only intended to provide utility static functions and not act as an object (with state), you could use delegation via a function template, which returns a (dummy) a object, followed by using the fact that an object of a given type, say A, can invoke non-static as well as static member functions.
namespace detail {
template <typename T = int>
struct AImpl {
static T x;
static T function(T number) {
return x = number;
}
};
template <typename T>
T AImpl<T>::x;
} // namespace detail
template<typename T = int>
constexpr detail::AImpl<T> a() { return {}; }
int main() {
const auto b_int = a().function(5);
const auto b_char = a<char>().function('a');
(void)b_int; (void)b_char;
}
If you in fact always wants to use deduction and never actually specify the type of the type template parameter (when other than int), you could exchange class template and its static data member and member function by a single function template that wraps a variable with static storage duration:
#include <type_traits>
template<typename T>
T function(T number) {
static T x;
return x = number;
}
int main() {
const auto b_int = function(5);
const auto b_char = function('a');
static_assert(std::is_same_v<decltype(b_int), const int>, "");
static_assert(std::is_same_v<decltype(b_char), const char>, "");
(void)b_int; (void)b_char;
}
This would be an entirely different (and more implicit) API, however.
Here is the example:
template <int n>
class A { };
class B {
public:
int foo() {
return a.n; // error
}
private:
A<10> a;
};
I want to get the value of instantiated class A<10>'s non-type template parameter in class B other than template A itself, is there a way to do this? Or should I use some other designs to avoid this problem?
You can't access other classes template parameters just like that. The other class has to expose it, for instance:
template <int n>
class A {
public:
static const int num = n;
};
Then you can access it as a.num (or A<10>::num of course)
If you can't get the type to cooperate (by publishing the parameter value), you can extract it yourself with a traits class:
template<class> struct A_param; // not defined
template<int N> struct A_param<A<N>> {
static constexpr int value = N;
};
// a more general implementation would probably want to handle cv-qualified As etc.
Then use A_param<decltype(a)>::value.
If you have a member A<10> your class B already know about the template parameter. Use that value instead. If the template parameter is indeed not named, let A define a member that reflects the template parameter.
1 -
class B {
public:
int foo() {
return n;
}
private:
const int n = 10;
A<n> a;
};
2 -
template <int n>
class A {
public:
static const int template_param = n;
};
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;
}