This question already has answers here:
C++ syntax for explicit specialization of a template function in a template class?
(9 answers)
Closed 8 years ago.
template<typename T>
class CConstraint
{
public:
CConstraint()
{
}
virtual ~CConstraint()
{
}
template <typename TL>
void Verify(int position, int constraints[])
{
}
template <>
void Verify<int>(int, int[])
{
}
};
Compiling this under g++ gives the following error:
Explicit specialization in non-namespace scope 'class CConstraint'
In VC, it compiles fine. Can anyone please let me know the workaround?
VC++ is non-compliant in this case - explicit specializations have to be at namespace scope. C++03, §14.7.3/2:
An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member.
An explicit specialization of a member function, member class or static data member of a class template shall be declared in the namespace of which the class template is a member.
Additionally you have the problem that you can't specialize member functions without explicitly specializing the containing class due to C++03, §14.7.3/3, so one solution would be to let Verify() forward to a, possibly specialized, free function:
namespace detail {
template <typename TL> void Verify (int, int[]) {}
template <> void Verify<int>(int, int[]) {}
}
template<typename T> class CConstraint {
// ...
template <typename TL> void Verify(int position, int constraints[]) {
detail::Verify<TL>(position, constraints);
}
};
Another way to solve it is by delegating to a private function and overloading that function. This way you still have access to member data of *this and to the outer template parameter type.
template<typename T>
struct identity { typedef T type; };
template<typename T>
class CConstraint
{
public:
template <typename TL>
void Verify(int position, int constraints[])
{
Verify(position, constraints, identity<TL>());
}
private:
template<typename TL>
void Verify(int, int[], identity<TL>)
{
}
void Verify(int, int[], identity<int>)
{
}
};
Just take the template specialization outside the class declaration.
gcc doesn't allow inline template specialization.
As another option, just deleting line
template<>
seems to work for me.
Even better: you can combine partial specialisation with default template arguments. This way modification to the VC++ code are minor, because calls to the specialised function do not need to be modified.
template <typename TL, class Dummy=int>
void Verify(int position, int constraints[])
{
}
template <class Dummy=int>
void Verify<int, Dummy>(int, int[])
{
}
You may not be able to explicitly specialize the member template, but you can partially specialize it. If you add a second parameter "int dummyParam" and also add it to the specialization, it should work with both compilers.
Not that I knew this more than 10 seconds ago, but googling on the same error, I ran into this link and it worked for my member template specialization.
Related
I am working on Visual Studio 2015 community edition
let's say I have, a simple class like this:
(The example below "should be" a compilable because it include all the necessary stuff, unfortunately, it produces an error).
#include <stdexcept>
template <typename T>
class class_foo
{
// members, methods, constructors. not important stuff...
// helper functions:
private:
class tag_aaa {}; // to resolve few things at compile-time, not run-time.
class tag_bbb {}; // - || -
template <typename tag>
void erase();
// for some reason this is not interpreted as an error by my compiler:
template<>
void erase<tag_aaa>();
template<>
void erase<tag_bbb>();
};
// catch-all-do-nothing "version"
// well, catch-all-throw-an-exception because call to this function is an obvious error.
// that should never occur.
template <typename T>
template <typename tag> inline
void class_foo<T>::erase()
{
throw std::runtime_error("Very weird error...");
}
template <>
template <typename T> inline
void class_foo<T>::erase<class_foo<T>::tag_aaa>()
{
// do some stuff...
}
template <>
template <typename T> inline
void class_foo<T>::erase<class_foo<T>::tag_bbb>()
{
// do some stuff...
}
int main()
{
class_foo<double> bar;
return 0;
}
The error:
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(36): error : partial specialization of class "class_foo<T>::erase<class_foo<T>::tag_aaa> [with T=T]" is not allowed
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(43): error : partial specialization of class "class_foo<T>::erase<class_foo<T>::tag_bbb> [with T=T]" is not allowed
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(51): warning : variable "bar" was declared but never referenced
I think about myself as a junior-hobbyist programmer, so certainly I am wrong, but I believe that both erase<class_foo<T>::tag_aaa>() and erase<class_foo<T>::tag_bbb>() are explicit specializations of the template <typename tag> void erase(); function. And as such, they are allowed. I believe that this error is due to some bad syntax but I can't find an error.
Question:
Is what I am trying to do, allowed?
If yes, what am I doing wrong?
If yes, what is the correct syntax for specializing this functions (erase)?
It look like full specialization of a template function but it's still partial specialization, hence the compilation error.
Why is it? Well, look at this specialization:
template <>
template <typename T>
inline void class_foo<T>::erase<class_foo<T>::tag_bbb>() {
// do some stuff...
}
You said it's a explicit specialization, but there is still a template parameter to fill! There's the parameter T yet to be known. So a specialization... that is still a template? That's a partial specialization!
Partial specialization of function is not allowed, for many reason. One of them is that it won't play nicely with overloading.
To effectively specialize the function, you must leave no template parameter to be known, something like this:
template<>
template<>
inline void class_foo<int>::erase<class_foo<int>::tag_bbb>() {
// do some stuff...
}
But it's not what you want.
Here's how I'd fix this problem. Use overloading instead of specializing:
template<typename T>
struct class_foo {
private:
struct tag_aaa {};
struct tag_bbb {};
void erase(tag_aaa) {
// Stuff when tag_aaa
}
void erase(tag_bbb) {
// Stuff when tag_bbb
}
};
Instead of invoking those like this:
erase<tag_aaa>(); // with specialization
You must invoke it like that:
erase(tag_aaa{}); // with overloading
There are 2 different specialization template forms in c++
One is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
The other is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
They can also be compiled in VS2013. I notice that the second implementation of specialization template situation is just lack of template<>
I want to know what the difference is between the 2 forms above.
Visual C++ is wrong.
The standard is very clear about this.
First,
Members of an explicitly specialized class template are defined in the
same manner as members of normal classes, and not using the template<>
syntax.
Meaning that, for explicit specialization of a class template, the member definition strictly do not require template<>.
Example:
template<class T>
struct A {
};
template<>
struct A<int> {
void f(int);
};
// template<> not used for a member of an
// explicitly specialized class template
void A<int>::f(int) { / ... / }
And,
A member or a member template of a class template may be explicitly
specialized for a given implicit instantiation of the class template,
even if the member or member template is defined in the class template
definition. An explicit specialization of a member or member template
is specified using the syntax for explicit specialization.
Meaning that, for a template that is not "explicit specialized", you can specialize its member, with the template<> (syntax for explicit specialization)
Example,
template<class T>
struct A {
void f(T);
};
// specialization
template<>
void A<int>::f(int);
The above examples are directly copied out from standard. To summarize, if the class is already explicitly specialized, do not use template<>, else if the class relies on implicit instantiation, use template<>.
Your first example compiles fine in Clang, and your second example fails to compile in Clang, you will get an error:
error: template specialization requires 'template<>'
template <class T> class mycontainer { ... };
template <> class mycontainer <char> { ... };
The first line is the generic template, and the second one is the specialization.
When we declare specializations for a template class, we must also define all its members, even those identical to the generic template class, because there is no "inheritance" of members from the generic template to the specialization.
http://www.cplusplus.com/doc/tutorial/templates/
There are a few questions already similar to this already on stack overflow, but nothing that seemd to directly answer the question I have. I do apologise if I am reposting.
I'd like to overload a few methods of a templated class (with 2 template parameters) with a partial template specialisation of those methods. I haven't been able to figure out the correct syntax, and am starting to think that it's not possible. I thought I'd post here to see if I can get confirmation.
Example code to follow:
template <typename T, typename U>
class Test
{
public:
void Set( T t, U u );
T m_T;
U m_U;
};
// Fully templated method that should be used most of the time
template <typename T, typename U>
inline void Test<T,U>::Set( T t, U u )
{
m_T=t;
m_U=u;
}
// Partial specialisation that should only be used when U is a float.
// This generates compile errors
template <typename T>
inline void Test<T,float>::Set( T t, float u )
{
m_T=t;
m_U=u+0.5f;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test<int, int> testOne;
int a = 1;
testOne.Set( a, a );
Test<int, float> testTwo;
float f = 1.f;
testTwo.Set( a, f );
}
I know that I could write a partial specialisation of the entire class, but that kinda sucks. Is something like this possible?
(I'm using VS2008)
Edit: Here is the compile error
error C2244: 'Test::Set' : unable to match function definition to an existing declaration
Thanks :)
You cannot partially specialize a member function without defining partial specialization of the class template itself. Note that partial specialization of a template is STILL a template, hence when the compiler sees Test<T, float>, it expects a partial specialization of the class template.
--
$14.5.4.3/1 from the C++ Standard (2003) says,
The template parameter list of a
member of a class template partial
specialization shall match the
template parameter list of the class
template partial specialization. The
template argument list of a member of
a class template partial
specialization shall match the
template argument list of the class
template partial specialization. A
class template specialization is a
distinct template. The members of the
class template partial specialization
are unrelated to the members of the
primary template. Class template
partial specialization members that
are used in a way that requires a
definition shall be defined; the
definitions of members of the primary
template are never used as definitions
for members of a class template
partial specialization. An explicit
specialization of a member of a class
template partial specialization is
declared in the same way as an
explicit specialization of the primary
template.
Then the Standard itself gives this example,
// primary template
template<class T, int I> struct A {
void f();
};
template<class T, int I> void A<T,I>::f() { }
// class template partial specialization
template<class T> struct A<T,2> {
void f();
void g();
void h();
};
// member of class template partial specialization
template<class T> void A<T,2>::g() { }
I hope the quotation from the Standard along with the example answers your question well.
The particular problem you're sketching is easy:
template< class T >
inline T foo( T const& v ) { return v; }
template<>
float foo( float const& v ) { return v+0.5; }
Then call foo from your Test::Set implementation.
If you want the full generality, then similarly use a helper class with static helper member functions, and partially specialize that helper class.
Cheers & hth.,
There's also another solution to the partial specialization problem, if you don't want to introduce additional functions, methods or classes to your code.
#include <type_traits>
template <typename T1, typename T2>
class C
{
void f(T1 t1);
}
template <typename T1, typename T2>
void C<T1, T2>::f(T1 t1)
{
if (std::is_same<T2, float>::value)
// Do sth
else
// Do sth
}
// InternalTemplate.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
template<class T>
struct LeftSide
{
static void insert(T*& newLink, T*& parent)
{
parent->getLeft() = newLink;
newLink->parent = newLink;
}
};
template<class T>
struct Link
{
T* parent_;
T* left_;
T* right_;
T*& getParent()const
{
return parent_;
}
template<class Side>
void plugIn(Link<T>*& newLink);
};
template<class T>
template<class Side>
void Link<T>::plugIn(Link<T>*& newLink)//<<-----why can't I type
//void Link<T>::plugIn<Side>(Link<T>*& newLink)<---<Side> next to plugIn
{
Side::insert(newLink,this);
}
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
I find it strange that I have to specify parameter for a class but cannot specify parameter for a function. Is there any reason why?
Function templates and class templates are complementary (I call them orthogonal, but you are free not to agree), and in template metaprogramming they actually serve orthogonal purposes.
Class templates allow you to pattern match on the template argument, ie. they provide partial specialization.
Function templates, to the contrary, don't allow partial specialization, but they allow template argument deduction, which means you don't have to write the template arguments explicitly (except for extra arguments, as in your example).
This, I think, explains the differences in syntax since they are different in what they can achieve. Moreover, function templates can have overloads, class templates cannot.
The way to combine both concepts is
1) to have helper class templates with static non template functions if you want partial specialization for function templates:
template <typename T>
struct doSomethingWithPointersHelper
{
static void act(T x) { ... }
};
template <typename T>
struct doSomethingWithPointersHelper<T*>
{
static void act(T* x) { ... }
};
// This acts as if we had a partial specialization
// for pointer types
template <typename T>
doSomethingWithPointers(T x)
{ return doSomethingWithPointersHelper<T>::act(x); }
There are other ways to achieve this in particular cases, but this approach always works.
2) To have helper template functions if you want to make use of argument deduction when constructing complex classes:
template <typename T, typename U>
struct MyComplexClass
{ ... };
template <typename T, typename U>
MyComplexClass<T, U> makeComplex(T t, U u)
{ return MyComplexClass<T, U>(t, u); }
in the standard library, you find make_pair, bind1st or mem_fun which make use of this technique.
$14/2 -
A template-declaration can appear only as a namespace scope or class scope declaration. In a function template declaration, the last component of the declarator-id shall be a template-name or operator-functionid (i.e., not a template-id). [ Note: in a class template declaration, if the class name is a simple-template-id, the declaration declares a class template partial specialization (14.5.5). —end note ]"
The standard forbids such a syntax explicitly. Refer this for more idea about template id / template name
You need to specialize on the Link struct in order to define it's template member function.
template<>
template<class Side>
void Link<int>::plugIn(Link<int>*& newLink)
{
Side::insert(newLink,this);
}
Gotta be honest, this makes my brain explode a little.
just now I had to dig through the website to find out why template class template member function was giving syntax errors:
template<class C> class F00 {
template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here
I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:
f.template bar<T>();
what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?
I got tripped up the first time I inherited a templated class from another templated class:
template<typename T>
class Base {
int a;
};
template<typename T>
class Derived : public Base<T> {
void func() {
a++; // error! 'a' has not been declared
}
};
The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:
template<typename T>
class Derived : public Base<T> {
using Base<T>::a;
void func() {
a++; // OK!
}
};
Alternatively, you can make it explicit that you are using a member of T:
void func {
T::a++; // OK!
}
This one got me upset back then:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write
f.foo::vector<int>();
GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:
"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
template "foo::vector" (declared at line 8) used in preference to
class template "std::vector" (declared at line 163 of
"stl_vector.h")
f.vector<int>(); // ambiguous!
The star of questions about templates here on SO: the missing typename!
template <typename T>
class vector
{
public:
typedef T * iterator;
...
};
template <typename T>
void func()
{
vector<T>::iterator it; // this is not correct!
typename vector<T>::iterator it2; // this is correct.
}
The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.
The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.
template <typename T>
void func()
{
T::staticTemplateFunc<int>(); // ambiguous
T::template staticTemplateFunc<int>(); // ok
T t;
t.memberTemplateFunc<int>(); // ambiguous
t.template memberTemplateFunc<int>(); // ok
}
Out of scope class member function definition:
template <typename T>
class List { // a namespace scope class template
public:
template <typename T2> // a member function template
List (List<T2> const&); // (constructor)
…
};
template <typename T>
template <typename T2>
List<T>::List (List<T2> const& b) // an out-of-class member function
{ // template definition
…
}