I have had problems (possibly mine) with template template parameters and clang. The following toy example compiles and runs under g++ 4.7.0, not clang++ 3.0 (based on LLVM 3.0), both ubuntu 12.04.
Toy example (test_1.cpp):
#include <iostream>
#include <memory>
struct AFn
{
void operator()()
{
; // do something
}
};
template<typename T>
struct impl
{
T *backpointer_;
};
template<typename S, template <typename> class T>
struct implT
{
T<S> *backpointer_;
};
template<typename>
class AClass;
template<>
struct implT<AFn, AClass>
{
implT(std::string message) :
message_(message)
{}
void operator()()
{
std::cout << " : " << message_ << std::endl;
}
std::string message_;
};
template<typename Fn>
class AClass
{
private:
std::shared_ptr<implT<Fn, AClass> > p_;
public:
AClass(std::string message) :
p_(std::make_shared<implT<Fn, AClass> >(message))
{}
void call_me()
{
p_->operator()();
}
};
int main(int argc, char **argv)
{
AClass<AFn> *A = new AClass<AFn>("AClass<AFn>");
A->call_me();
delete A;
return 0;
}
clang output:
*****#ely:~$ clang++ -std=c++11 test_1.cpp -o test_1
test_1.cpp:47:30: error: template argument for template template parameter must be a class template or
type alias template
std::shared_ptr<implT<Fn, AClass> > p_;
^
test_1.cpp:47:40: error: C++ requires a type specifier for all declarations
std::shared_ptr<implT<Fn, AClass> > p_;
^~
test_1.cpp:50:36: error: template argument for template template parameter must be a class template or
type alias template
p_(std::make_shared<implT<Fn, AClass> >(message))
^
3 errors generated.
I can't make sense of the first error. It compiles and runs fine with gcc/g++ 4.7.0. Any help would be appreciated.
As noted, it's a Clang bug. AClass there is an injected-class-name, a unique grammatical construct which is both a class-name and a template-name.
Another workaround is to say AClass::template AClass. This avoids needing to qualify AClass with its enclosing namespace.
The same thing happens for me with Clang 3.3.
The solution -- or workaround -- from this SO question is to replace AClass with ::AClass on lines 47 and 50, and then it compiles happily.
To be honest template template parameters make my head hurt. The referenced question suggests it's a Clang bug, but I'm not enough of an expert to be able to say.
Related
The following snippet is compiled fine by gcc, icc and msvc (latest question), but trips clang with <source>:6:9: error: calling a private constructor of class 'B<int>' in the marked line. Yet it works fine for the free template function, as shown in the code:
struct A {
template<class T>
static void create () {
T();
}
};
template<class T>
void create() {
T();
}
template<typename T>
struct B {
friend void A::create<B>();
friend void create<B>();
private:
B() = default;
};
int main() {
A::create<B<int>>(); // clang trips here
create<B<int>>(); // fine!
}
What might be the difference between a static template member of non-template class and free template function in this context?
I found a bug reported for Clang, "Access to a public template alias declaration that refers to friend's private nested type is not allowed" which seems similar to this issue as it relates to a friend (template within a structure as in the OP) accessing a private member of a class.
The failed test case is:
struct FooAccessor
{
template <typename T>
using Foo = typename T::Foo;
};
class Type
{
friend struct FooAccessor;
using Foo = int;
};
int main()
{
FooAccessor::Foo<Type> t;
}
The result is:
$ clang++ test.cpp -std=c++11
test.cpp:4:5: error: 'Foo' is a private member of 'Type'
using Foo = typename T::Foo;
^
test.cpp:11:11: note: implicitly declared private here
using Foo = int;
^
1 error generated.
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.
This code compiles with clang 3.7.1 (with no diagnostic) but fails with GCC 5.3.0 (live example):
#include <iostream>
template<typename T>
struct A {
void foo()
{
static_cast<T*>(this)->implementation();
}
};
struct Crtp : A<Crtp> {
template<typename T>
friend struct A;
private:
void implementation() { std::cout << "implementation()\n"; }
};
int main()
{
Crtp c;
c.foo();
}
GCC's error message is the following:
main.cpp:13:16: error: specialization of 'A' after instantiation
friend struct A;
Which one is right and why? Is it a bug of GCC / clang?
Seems to be an old g++ bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52625).
Reported and never corrected, if I understand correctly,
I think this is gcc's bug.
A template friend class declaration is only a declaration, not a definition.
Redeclaration of class template is allowed unless it has different class-key (see N4527 14.5.1.4).
Specialization or instantiation can occur twice or more.
Explicit specialization can occur only once(N4527 14.7.3.6).
Then, gcc's diagnostics is odd because there is no explicit specialization.
We do have some template name resolution odds:
struct Crtp : A<Crtp> {
A x; // A refers to A<Crtp>
};
Now things are clear:
template<typename T> friend struct A;
refers to:
template<typename T> friend struct A<Crtp>;
which is... yeah, partial specialization (really tricky one).
So GCC is correct here.
What do you really need is:
struct Crtp : A<Crtp> {
friend struct A;
private:
void implementation() { std::cout << "implementation()\n"; }
};
I have had problems (possibly mine) with template template parameters and clang. The following toy example compiles and runs under g++ 4.7.0, not clang++ 3.0 (based on LLVM 3.0), both ubuntu 12.04.
Toy example (test_1.cpp):
#include <iostream>
#include <memory>
struct AFn
{
void operator()()
{
; // do something
}
};
template<typename T>
struct impl
{
T *backpointer_;
};
template<typename S, template <typename> class T>
struct implT
{
T<S> *backpointer_;
};
template<typename>
class AClass;
template<>
struct implT<AFn, AClass>
{
implT(std::string message) :
message_(message)
{}
void operator()()
{
std::cout << " : " << message_ << std::endl;
}
std::string message_;
};
template<typename Fn>
class AClass
{
private:
std::shared_ptr<implT<Fn, AClass> > p_;
public:
AClass(std::string message) :
p_(std::make_shared<implT<Fn, AClass> >(message))
{}
void call_me()
{
p_->operator()();
}
};
int main(int argc, char **argv)
{
AClass<AFn> *A = new AClass<AFn>("AClass<AFn>");
A->call_me();
delete A;
return 0;
}
clang output:
*****#ely:~$ clang++ -std=c++11 test_1.cpp -o test_1
test_1.cpp:47:30: error: template argument for template template parameter must be a class template or
type alias template
std::shared_ptr<implT<Fn, AClass> > p_;
^
test_1.cpp:47:40: error: C++ requires a type specifier for all declarations
std::shared_ptr<implT<Fn, AClass> > p_;
^~
test_1.cpp:50:36: error: template argument for template template parameter must be a class template or
type alias template
p_(std::make_shared<implT<Fn, AClass> >(message))
^
3 errors generated.
I can't make sense of the first error. It compiles and runs fine with gcc/g++ 4.7.0. Any help would be appreciated.
As noted, it's a Clang bug. AClass there is an injected-class-name, a unique grammatical construct which is both a class-name and a template-name.
Another workaround is to say AClass::template AClass. This avoids needing to qualify AClass with its enclosing namespace.
The same thing happens for me with Clang 3.3.
The solution -- or workaround -- from this SO question is to replace AClass with ::AClass on lines 47 and 50, and then it compiles happily.
To be honest template template parameters make my head hurt. The referenced question suggests it's a Clang bug, but I'm not enough of an expert to be able to say.
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);