call to templated member of templated base class fails [duplicate] - c++

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 8 years ago.
I have a problem which seems to be already discussed here in:
CPP templated member function specialization
But the solution with this->template did not work with my example.
The following code fails with:
error: invalid operands of types '<unresolved overloaded function type>' and 'int'
to binary 'operator<'
with gcc 4.8.1
class Base { public: virtual int Do(){return 0;} };
class State1: public Base {};
class State2: public Base {};
template <typename ... T> class SM;
template <class StateBase, class HeadState, class ... States >
class SM<StateBase, HeadState, States...> : public SM< StateBase, States...>
{
protected:
HeadState headState;
template<int cnt> StateBase* GetNextState ( unsigned int index ) { return headState; }
};
template <class StateBase, class HeadState>
class SM< StateBase, HeadState>
{
protected:
HeadState headState;
template<int cnt> StateBase* GetNextState ( unsigned int index ) { return headState; }
};
template <class StateBase, class ... States >
class TopSM: public SM< StateBase, States...>
{
public:
void DoIt()
{
// following code fails with
// error: invalid operands of types '<unresolved overloaded function type>' and 'int' to binary 'operator<'
int nextState = this->template SM< StateBase, States...>::GetNextState <1>( 1 );
}
};
TopSM<Base, State1, State2> sm;
int main()
{
sm.DoIt();
return 0;
}

You need another template before GetNextState. If there are template arguments after an identifier and a ., ->, or :: before, and it's a member of something dependent on a template parameter, there needs to be a template keyword to disambiguate the less-than sign.
int nextState = this->template SM< StateBase, States...>::template GetNextState <1>( 1 );

Almost there, you need another template
int nextState = this->template SM< StateBase, States...>::template GetNextState <1>( 1 );
~~~~~~~~
The problem is that, because GetNextState comes from a template parameter, it doesn't know whether it's a static variable, function, template function or anything. The parser needs to continue, so it makes the assumption that its not a template function, so the < is parsed as a less-than operator, instead of the beginning of a template parameter list. From there, the parser gets confused and you get the error about invalid operands to >.

Related

Template class with template constructor specialization for initializing a templated base class

I have a template base class with a template parameter of type bool. The constructor parameter list of this base class depends on whether the template parameter is true or false. I want to derive from this class another template class with a template parameter that is any type. I need this derived class to call the correct constructor of that Base class depending on traits of that type.
The example below is not all-encompassing. Integral or not, the base class template bool could be for any type trait. Also, the type passed to the template parameter of the derived class could be any type.
I've tried several different methods for trying to syntax this thing out, but the closest I've gotten is with the code below. However it errors due to the fact that the derived class needs to be fully specialized.
#include <type_traits>
using namespace std;
template<bool IsIntegral> struct Base
{
template<bool IsI = IsIntegral,
typename I = typename enable_if<IsI>::type>
Base(int param) {}
template<bool IsI = IsIntegral,
typename I = typename enable_if<!IsI>::type>
Base() {}
};
template<class T> class CL :
Base<is_integral<T>::value>
{
public:
template<bool U = is_integral<T>::value> CL();
};
template<>
template<class T>
CL<T>::CL<true>() : // error: ISO C++ forbids declaration of ‘CL’ with no type [-fpermissive]
// CL<T>::CL<true>() :
// ^
// error: non-type partial specialization ‘CL<true>’ is not allowed
// error: no declaration matches ‘int CL<T>::CL()’
// CL<T>::CL<true>() :
// ^~~~~
Base(4) { }
template<>
template<class T>
CL<T>::CL<false>() // error: ISO C++ forbids declaration of ‘CL’ with no type [-fpermissive]
// CL<T>::CL<true>() :
// ^
// error: non-type partial specialization ‘CL<true>’ is not allowed
// error: no declaration matches ‘int CL<T>::CL()’
// CL<T>::CL<true>() :
// ^~~~~
{ }
int main () {
// Base<true> a; // won't compile as expected
Base<true> a(4);
// Base<false> b(4); // won't compile as expected
Base<false> b;
CL<int> c; // integral
CL<int*> d; // non-integral
// should work for any types other than int and int*
return 0;
}
I need to keep the type T generic and can't fully specialize the class CL. What is the correct syntax for this? Is there a workaround?
I'm using gcc-g++ version 8.3.0-6.
Thanks in advance!
After playing around with this, a little bit, I came up with this, which I guess falls under the category of "workaround", which you are willing to consider:
template<class T> class CL :
Base<is_integral<T>::value>
{
public:
CL() : CL{ is_integral<T>{} } {}
template<typename U=T>
CL(std::true_type) : Base<true>{4} {}
template<typename U=T>
CL(std::false_type)
{
}
};
Your derived class should be:
template<class T> class CL :
Base<is_integral<T>::value>{
public:
using base_t = Base<is_integral<T>::value>;
using base_t::base_t;
};
The using base_t::base_t; makes you inherit the constructors from your base class (available since c++11).
In your example you should also change:
CL<int> c; // integral
into, e.g.:
CL<int> c(10); // integral
C++20 and requires clauses
Prior to C++20, I would recommend tag dispatch to private delegating constructors as shown in #SamVarshavchik's answer.
Once you may use C++20, you can easily construct these kind of relations using a requires clause:
#include <type_traits>
template <bool IsIntegral>
struct Base {
Base(int param) requires IsIntegral {}
Base() requires (!IsIntegral) {}
};
template<typename T>
class CL : Base<std::is_integral<T>::value> {
static constexpr bool kIsIntegral = std::is_integral_v<T>;
public:
CL() requires kIsIntegral : CL::Base(4) {}
CL() requires (!kIsIntegral) : CL::Base() {}
};

No type named 'type' in CTRP derived class

I've been experimenting with the Curiously Recurring Template Pattern for a generic single-argument functor and have two implementations: one using a template template parameter which works and a second where I try to access the derived Functor::type in the interface class. In the latter example, the compiler (gcc 5.4.0) reports
error: no type named 'type' in 'struct Cube< double >'
template<class T, template<class> class Functor>
class FunctorInterface_1 {
private:
const Functor<T> &f_cref;
public:
FunctorInterface_1() : f_cref(static_cast<const Functor<T>&>(*this)) {}
T operator() ( T val ) const { return f_cref(val); }
}; // FunctorInterface_1 (works)
template<class Functor>
class FunctorInterface_2 {
private:
const Functor &f_cref;
public:
using Ftype = typename Functor::type;
FunctorInterface_2() : f_cref(static_cast<const Functor&>(*this)) {}
Ftype operator() ( Ftype val ) const { return f_cref(val); }
}; // FunctorInterface_2 (no type in Functor!)
I then try to compile with T=double in main() of the following two classes:
template<class T>
struct Square : public FunctorInterface_1<T,Square> {
T operator()( T val ) const { return val*val; }
}; // Square
template<class T>
struct Cube : public FunctorInterface_2<Cube<T>> {
using type = T;
T operator() ( T val ) const { return val*val*val; }
}; // Cube
Can the FunctorInterface_2/Cube example be modified to work, or
is it necessary for the interface class to be templated on T as
in the first example? Thanks!
EDIT: Using gcc -std=c++14, I can get the second example to compile and run
by using auto return and argument types in FunctorInterface_1::operator(), however, as I understand, auto argument types are not part of the C++14 standard.
EDIT 2: Well I feel a bit thick. I just realized that I could template FunctorInterface_1::operator() on a new parameter, however, for the application I have in mind, I would really like my base class to be able to access types defined in the derived class.
When the line
using Ftype = typename Functor::type;
is processed in the base class, the definition of Functor is not available. Hence, you can't use Functor::type.
One way to get around this limitation is to define a traits class.
// Declare a traits class.
template <typename T> struct FunctorTraits;
template<class Functor>
class FunctorInterface_2 {
private:
const Functor &f_cref;
public:
// Use the traits class to define Ftype
using Ftype = typename FunctorTraits<Functor>::type;
FunctorInterface_2() : f_cref(static_cast<const Functor&>(*this)) {}
Ftype operator() ( Ftype val ) const { return f_cref(val); }
}; // FunctorInterface_2 (no type in Functor!)
// Forward declare Cube to specialize FunctorTraits
template<class T> struct Cube;
// Specialize FunctorTraits for Cube
template <typename T> struct FunctorTraits<Cube<T>>
{
using type = T;
};
template<class T>
struct Cube : public FunctorInterface_2<Cube<T>> {
using type = T;
T operator() ( T val ) const { return val*val*val; }
}; // Cube
Working code: https://ideone.com/C1L4YW
Your code could be simplified to
template<typename TDerived> class
Base
{
using Ftype = typename TDerived::type;
};
template<typename T> class
Derived: public Base<Derived<T>>
{
using type = T;
};
Derived<int> wat;
It does not work because at the point of Base instantiation Derived class is not complete, and compiler is not aware of Derived::type existence yet.
You have to understand that when you instantiate Cube<T> FunctionInterface_2<Cube<T>> gets instantiated first. This means that Cube<T> is an incomplete type while this is happening.
So when the compiler gets to the line using Ftype = typename Functor::type; Functor is incomplete and you cannot access any of its nested types.
In your case you can change FunctionInterface_2 to:
template<class Functor>
class FunctorInterface_2 {
private:
const Functor &f_cref;
public:
FunctorInterface_2() : f_cref(static_cast<const Functor&>(*this)) {}
template <class TT>
auto operator() ( TT && val ) -> decltype(f_cref(val)) const { return f_cref(val); }
};
So now accessing information about Functor is delayed until you call the operator() from FunctionInterface_2 at which point FunctionInterface_2 and Cube are fully instantiated.
Note: This question has already been answered by #r-sahu, but I'd like to elaborate on this and address clang's output specifically.
The problem can be demonstrated on a much smaller code sample: (#vtt suggested something similar)
template <typename _CRTP>
struct A {
using _C = typename _CRTP::C;
};
struct B : public A<B> {
using C = int;
};
Compiling that with clang will result in completely misleading error message: (godbolt)
<source>:3:32: error: no type named 'C' in 'B'
using _C = typename _CRTP::C;
~~~~~~~~~~~~~~~~^
<source>:6:19: note: in instantiation of template class 'A<B>' requested here
struct B : public A<B> {
^
1 error generated.
GCC's error message is a little more helpful: (godbolt)
<source>: In instantiation of 'struct A<B>':
<source>:6:19: required from here
<source>:3:33: error: invalid use of incomplete type 'struct B'
3 | using _C = typename _CRTP::C;
| ^
<source>:6:8: note: forward declaration of 'struct B'
6 | struct B : public A<B> {
| ^
As suggested in the accepted answer, implementing a trait type fixes the issue:
// this declaration must appear before the definition of A
template <typename _A>
struct a_traits;
template <typename _CRTP>
struct A {
// `a_traits<_CRTP>::type` is an incomplete type at this point,
// but that doesn't matter since `A` is also incomplete
using _C = typename a_traits<_CRTP>::type;
};
// this specialization must appear before the definition of B
template <>
struct a_traits<struct B> { // adding the type specifier `struct` will declare B
using type = int;
};
// specifying the template parameter will complete the type `A<B>`, which works since
// `a_traits<B>` is already complete at this point
struct B : public A<B> {
using C = int;
};

Referring to base class property from a derived template specialization function

Let's say we have a base class that does nothing but contain other values and performs certain operations on them, such as printing them:
template <typename T>
class Base {
public:
Base (const T& t) : value(t) {}
void printValue () {
cout << value << endl;
}
protected:
T value;
};
Then let's say we want to derive from this template class to provide additional functionality. For the sake of this discussion, I'll keep it simple and just say we're adding the ability to change the contained object's value. Setting value = t will not work in derived template functions, but qualifying the value with this-> will:
template <typename T>
class Derived: public Base<T> {
public:
Derived (const T& t) : Base<T>(t) {}
void setValue (const T& t) {
this->value = t;
}
};
But now, let's say I want to specialize a function for certain types of instantiated objects. Say, if a type can be incremented, like int, I want to provide that functionality:
template <>
class Derived<int> {
public:
void increment () {
this->value++;
}
};
This does not work, because the compiler will not recognize the base class' property value. I've also tried inserting a using Base<int>::value declaration before the increment, and it still doesn't work (at least, not with g++). I get a compiler error ‘Base<int>’ is not a namespace
Is there a way to refer to base template class' properties from a specialized template function? Using this-> works for derived template classes, but not for specialized functions for derived classes. I've also found that puting using Base<T>::value in Derived::setValue rather than using this-> doesn't work, although I thought it should. Any thoughts?
Update: This is the complete code:
template <typename T>
class Base {
public:
Base (const T& t) : value(t) {}
void printValue () {
cout << value << endl;
}
protected:
T value;
};
template <typename T>
class Derived: public Base<T> {
public:
Derived (const T& t) : Base<T>(t) {}
void setValue (const T& t) {
this->value = t;
}
};
template <>
class Derived<int>: public Base<int> {
public:
void increment () {
//using Base<int>::value;
this->value++;
}
};
And these are the errors:
templatebase.cpp: In function ‘int main()’:
templatebase.cpp:36:21: error: no matching function for call to ‘Derived<int>::Derived(int)’
templatebase.cpp:36:21: note: candidates are:
templatebase.cpp:27:7: note: constexpr Derived<int>::Derived(const Derived<int>&)
templatebase.cpp:27:7: note: no known conversion for argument 1 from ‘int’ to ‘const Derived<int>&’
templatebase.cpp:27:7: note: constexpr Derived<int>::Derived(Derived<int>&&)
templatebase.cpp:27:7: note: no known conversion for argument 1 from ‘int’ to ‘Derived<int>&&’

Type deduction template functions c++ [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 8 years ago.
I have to following example code. In this code I have two template classes each with a template function. One of the classes has an object of the other class and in the template function it calls the template of the other class.
template<typename T>
class A{
public:
A(T a): a(a){}
template< typename V> V foo(){
return this->a;
}
private:
T a;
};
template<typename T>
class B{
public:
B( A<T> a): a(a){}
template<typename V>V foo2(){
return this->a.foo<V>();
}
private:
A<T> a;
};
int
main()
{
A<int> a(5);
double aTest = a.foo<double>();
B<int> b(a);
double c = b.foo2< double >();
}
I need to provide the template element after the function call, because automatic type deduction does not work for functions, were only the return type depends on the template parameter. This works for aTest. But when I add the next two lines I get the following compiler error:
build/main.cpp: In member function 'V B<T>::foo2()':
build/main.cpp:32:23: error: expected primary-expression before '>' token
return this->a.foo<V>();
^
build/main.cpp:32:25: error: expected primary-expression before ')' token
return this->a.foo<V>();
You need to use:
template<typename V>V foo2(){
return this->a.template foo<V>();
}
To find gory details of why you need to use template in the call to a.foo, please take a look at this SO answer: https://stackoverflow.com/a/613132/434551

"Transparency" of a template template argument (missing template argument) [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 8 years ago.
To put it somewhat vaguely, from the snippet (tt.cc) below it seems to me as if the template template notion lacked some kind of a "transparency". While I don't seem to fathom what other template argument should A::f() be provided (besides the template template one), I might as well be just missing some banality here.
template <class T>
class A {
public:
template< template<class> class U >
void f( int i ) {
// ...
}
};
template< class T, template<class> class U >
class B {
public:
void f( int i ) {
A<T> a;
a.f<U>( i );
}
};
int main() {
return 0;
}
The error message it provides is:
g++ ./tt.cc -o tt
./tt.cc: In member function ‘void B<T, U>::f(int)’:
./tt.cc:17:10: error: missing template arguments before ‘>’ token
a.f<U>( i );
^
Compilation exited abnormally with code 1
Any ideas greatly appreciated.
What you are seeing is the compiler interpreting the > token inside f<U> as the inequality operator. You need to add .template to let the compiler know you mean a template argument.
void f( int i ) {
A<T> a;
a.template f<U>( i );
}
Live Example.
See also Where and why do I have to put the “template” and “typename” keywords?.