I'm getting an error when compiling a code that can be trivialized as follows:
#include<iostream>
template <class T>
class A
{
protected:
T protectedValue;
template<class TT>
class insideClass
{
public:
TT insideClassValue;
};
};
template<class T>
class B : public A<T>
{
public:
void print(T t)
{
insideClass<T> ic; // <-- the problem should be here
ic.insideClassValue = t;
std::cout << ic.indideClassValue << std::endl;
};
};
int main()
{
double v = 2.;
B<double> b;
b.print(v);
return 0;
};
The compiler (g++) gives the following error:
main.C: In member function ‘void B<T>::printA()’:
main.C:23:4: error: ‘insideClass’ was not declared in this scope
main.C:23:17: error: expected primary-expression before ‘>’ token
main.C:23:19: error: ‘ic’ was not declared in this scope
I figured out that if class A is not a template class, the compilation will not give any error.
I do not understand why making class A a template class results in the described error.
Any idea about the reasons and how to fix the problem?
Without qualification insideClass is a non-dependent name which is looked up during phase 1 look-up. Since the definition of the base depending on a template argument isn't known, names from the base class are ignored and the name isn't found. Qualification and possibly adding typename in a strategic place should solve the problem (thanks to remyabel for the notation):
typename A<T>::template insideClass<T> ic;
The template keyword is needed to indicate that what's coming is a template and the typename is needed to indicate that happens to be a type. Getting the correct spelling of what a dependent name is supposed to be is sometimes not entirely straight forward. A SSCCE showing the problem is here and the solution is here.
Something like this:
typedef typename A<T>::template insideClass<T> ic;
public:
void print(T t)
{
ic ic;
ic.insideClassValue = t;
std::cout << ic.insideClassValue << std::endl;
};
Related
The following code can be compiled with gcc(4.8 and up), while the MSVC (Visual Studio 2017, _MSC_VER 1910) gives error C2244: 'A::func': unable to match function definition to an existing declaration.
#include <iostream>
template<typename T, bool isInt= std::is_integral<T>::value >
class B
{
public:
using RET = T;
};
template <typename T>
class B <T, false>
{
public:
using RET = void;
};
template<typename T>
class A
{
using type = T;
public:
typename B<type>::RET func();
};
template<typename T>
typename B<typename A<T>::type>::RET A<T>::func()
{
std::cout << "func" << std::endl;
return 0;
}
int main()
{
A<int> a;
a.func();
return 0;
}
Full error message from MSVC:
error C2244: 'A<T>::func': unable to match function definition to an existing declaration
note: see declaration of 'A<T>::func'
note: definition
note: 'B<A<T>::type,std::is_integral<T>::value>::RET A<T>::func(void)'
with
[
T=A<T>::type
]
note: existing declarations
note: 'B<T,std::is_integral<_Ty>::value>::RET A<T>::func(void)'
It can compile if I eliminate the template specialization in class B.
template<typename T>
class B
{
public:
using RET = T;
};
It can also compile if I don't use the type alias in class A.
template<typename T>
class A
{
public:
typename B<T>::RET func();
};
template<typename T>
typename B<T>::RET A<T>::func()
{
std::cout << "func" << std::endl;
return 0;
}
And it can also compile if class A is not template.
class A
{
using type = int;
public:
typename B<type>::RET func();
};
It seems that the MSVC does not well support the mix use of template class, type alias and template specialization when separating the class member declaration and definition. I am not sure if there's a special term for this usage. Will the MSVC support this in newer version? Or any existing compile option can fix it?
This issue has been reported to visual studio developer community.
https://developercommunity.visualstudio.com/content/problem/225941/error-c2244-unable-to-match-function-definition-to.html
encountered the same problem today. I guess this is a bug in MVSC. In 15.9 it still exists.
I was wondering why below code does not compile with gcc (4.6.3) while it works perfectly fine using cl. I can obviously compile it with gcc by removing the template argument of the DoSomething function. Nonetheless I'd like to understand why the syntax below is not correct.
Thanks for any hints.
template <class T>
class Base {
public:
template <class B>
struct Var1 {
B var1_var;
};
Base() {};
~Base() {};
template <class V> void DoSomething(V val) {
std::cout << val.var1_var << std::endl;
}
};
template <class T>
class Derived : public Base<T> {
public:
Derived() {};
~Derived() {};
void Test() {
typename Base<T>::template Var1<int> val;
val.var1_var = 5;
Base<T>::DoSomething<typename Base<T>::template Var1<int> >(val); //error: expected ‘(’ before ‘>’ token
}
};
int main(int, char**) {
Derived<double> bla;
bla.Test();
return 0;
}
The problem is that Test is a nondependant name (it does not involve T) so the compiler won't look in dependant base class while looking for the function Dosomething.
You can solve this problem like you did (with 0x499602D2 's answer), but it will not allow virtual dispatch mechanism. You can solve this just by using this->DoSomething(val) also, that will enable virtual dispatch.
More information here.
You need another template:
Base<T>::template DoSomething<typename Base<T>::template Var1<int> >(val);
// ^^^^^^^^
Update: You also don't need to provide the template parameter. You can allow template argument deduction to do it for you:
DoSomething(val);
This is regarding a test case which involves default argument
deduction/substitution. The test case can be summarized as :
template <class T, class = typename T::I>h(T){}
template <class T, class = typename T::I>j(T){}
class A
{
typedef int I;
friend void h<A>(A);
};
int main()
{
A a;
h(a);
j(a);
}
gcc-4.8.1 throws error for function j, since it has been not been declared friend nor it is private to class A and hence violates access rule for private member I(which is valid). gcc does not throw error for function h since it has been declared as friend to class A and hence can access private member I.
Clang throws error for both the functions. Error for function j (not declared friend is valid and as expected), but it throws error even for friend function h (error : deduction of default arg failed since I is a private member of class A). This violates the accessibility of the friend function.
I checked the code path. While clang is able to deduce the default argument, it checks for access rules before doing any substitution, and gives error. Can someone please provide guidance as to how should this be fixed?
You forgot the return type for the template functions.
This should solve the problem :
template <class T, class = typename T::I> void h(T){}
template <class T, class = typename T::I> void j(T){}
After fixing above errors, I still got errors, because
you declared the typedef in the private section. You need to make it public
you declared function friend wrongly. It has two template arguments (A::I will not work, since A is not complete type)
Fully compilable problem is here :
#include <iostream>
// Type your code here, or load an example.
template <class T, class = typename T::I> void h(T t){std::cout<<t.a<<std::endl;}
template <class T, class = typename T::I> void j(T t){std::cout<<t.a<<std::endl;}
class A
{
friend void h<A,int>(A);
friend void j<A,int>(A);
public :
typedef int I;
private :
int a;
};
int main()
{
A a;
h(a);
j(a);
}
I'm trying to compile some Microsoft Visual C++ code using g++. Now I've come across a compiler error which I really can't understand. The (simplified) code looks like this:
template<int X> struct A {
template<class Ret> static Ret call() {
return 0;
}
};
template<int X> struct B : A<X> {
int f() {
return A<X>::call<int>();
}
};
When I try to compile this with g++ (version 4.4.5), I get the following error:
main.cpp: In member function int B<X>::f():
main.cpp:16: error: expected primary-expression before int
main.cpp:16: error: expected ; before int
main.cpp:16: error: expected unqualified-id before > token
If I remove the template type (Ret) from method A::call, the code compiles just fine. Can anybody see whats wrong here?
Thanks!
You need the template keyword:
return A<X>::template call<int>();
call is a dependent name, meaning that its signification depends on a template parameter, which is not known when the compiler process f(). You need to indicate that call is a function template by prefixing it with the template keyword.
The same thing happens when you try to access a nested type: you need to add the typename keyword to indicate that the name denotes a type:
template <typename T>
struct A { typedef int type; };
template <typename T>
void f()
{
typename A<T>::type i = 0; // notice "typename" here
}
And sometimes you even need to mix both:
template <typename T>
struct A
{
template <typename U>
struct inner { };
};
template <typename T>
void f()
{
typename A<T>::template inner<int> var;
}
The use of these two keywords is thoroughly explained in the answers to this question: Where and why do I have to put the “template” and “typename” keywords? (thanks to #Björn Pollex for finding the link).
A is a template, and without knowing X the compiler can't determine the contents of A<X>. Especially it doesn't know that call will end up being a template.
To tell that to the compiler you have to use the template keyword:
template<int X> struct B : A<X> {
int f() {
return A<X>::template call<int>();
}
};
You have to specify that the function you're calling is a template, as it's part of a template class. The compiler is not aware that any given A<X> has a template function named call, and therefore you need to help it.
template<int X> struct B : A<X> {
int f() {
return A<X>::template call<int>();
}
};
If I have a template base class with a template method :
template <typename T>
class S
{
public:
template <typename U>
void f(U p, typename enable_if<is_same<T, U> >::type*dummy = 0)
{
std::cout << p << std::endl;
}
};
For the example, I simplify the method : it must "exists" only if T == U
If A is this class:
class A : public S<int> {};
Then I have what I want:
int i = 1;
A a;
a.f(i);
compiles, but
double d = 2.0;
a.f(d);
doesn't compile : error: no matching function for call to ‘A::f(double&)’
It is the expected behavior.
Now let's A inherit from S<double> also :
class A : public S<int>, public S<double> {};
Then the following code doesn't compile:
int i = 1;
A a;
a.f(i);
error: request for member ‘f’ is ambiguous
error: candidates are: template<class U> void S::f(U, typename
boost::enable_if<boost::is_same<T, U>, void>::type*) [with U = U, T =
double]
error: template<class U> void S::f(U, typename
boost::enable_if<boost::is_same<T, U>, void>::type*) [with U = U, T =
int]
I expected there is no ambiguity : f<int> exists only for S<int>
In the compiler error, we can notice that T is known when this piece of code is compiled, but not U (U = U).
Any explanation or "workaround" ?
Try this:
a.S<int>::f(i);
...or alternatively inject the function into A, e.g.
class A : public S<int>, public S<double>
{
public:
using S<int>::f;
using S<double>::f;
};
You are right it only exists in S, but two times. Once for each type, int and double. So in your case you will need to specify exactly which function you want to call. The solution from Nim works just like that.
Others have given good workarounds, but I want to answer that other question you had
I expected there is no ambiguity : f<int> exists only for S<int>.
You said a.f(i) so it first needs to look for name f in A. It finds two fs. In S<int> and S<double>. At name lookup time, it does not know yet that it later could have only selected S<int>::f as a winner because S<double>::f would be thrown away by SFINAE. The clear separation of name lookup and overload resolution and template argument deduction does not allow such intermingling.