I'd like to specialize a template function to take non-pointer types and if in case it gets a pointer I'd like to call it without the *.
I'm wondering if there's a way without using std::remove_pointer.
for example I'd like to do something like this:
template<typename T>
void setName() {
name = __PRETTY_FUNCTION__;
}
template<typename T>
void setName<T*>() {
setName<T>();
}
name is defined as a private data member.
Your idea is correct but partial function template specialization is not allowed in C++. Fortuately partial class template specialization is allowed so you can use static method workaround (see specialization of setName_impl below) and if needed function template wrapper (see setName() below):
template<typename T>
struct setName_impl{
static void exec() { }
};
template<typename T>
struct setName_impl<T*>{
static void exec() {
setName<T>::exec();
}
};
template<typename T>
void setName() {
setName_impl<T>::exec();
}
Related
I have to assign the following member of a struct:
esp_err_t (*handler)(httpd_req_t *r);
As you can see, it is a function pointer. I have a generic template function that I would like to assign as handler:
template <class Tmsg>
esp_err_t HandleRpc(httpd_req_t *req){...}
I am assigning the handler member inside a generic template class, so I have a generic type argument Tpayload:
httpd_uri_t cfg = {
...
.handler = HandleRpc<Tpayload>,
...
};
I get:
expected primary-expression before '>' token
The issue lies in the fact that I can't pass a member method pointer (I.E. esp_err_t (RpcServer::*)(...)), but RpcServer is a generic template class (I.E. has a template with one generic parameter). So I thought that by creating a generic template function outisde the class (global scope?), and passing the RpcServer instance into that function, I would be able to retrieve my instance of RpcServer<T> and all would be well.
Here is the smallest amount of code I could come up with to reproduce the issue:
int main()
{
}
template <class T>
class RpcServer{
public:
void RegisterHandler();
};
struct HandlerInfo{
void (*handler)();
};
template <class T>
void Handle(RpcServer<T> test)
{
}
template <class T>
void RpcServer<T>::RegisterHandler(){
HandlerInfo info = {
.handler = Handle<T>;
};
}
Am I missing the obvious, or is what I am trying to do going to require some uglier trickery?
struct HandlerInfo{
void (*handler)();
};
handler is a pointer to a function that takes no parameters, and doesn't return anything. You can set this pointer to point to any function. As long as it takes no parameters, and doesn't return anything (its return type is void). There are no exceptions to this, this is how C++ works, it is a strongly-typed language.
template <class T>
void Handle(RpcServer<T> test)
{
This is a template for a function that takes one parameter. The type of the parameter is not material. The point is that every instance of this template will be a function that takes exactly one parameter, always.
In C++, a pointer to a function that has no parameters can only be set to point to such a function. You cannot set this function pointer to point to a function that takes one parameter, or two parameters, or ten parameters. It can only be set to a function that takes exactly zero parameters. That's because that's what the pointer points to.
If you were to change the template function so that it takes no parameters, then this would work, of course:
int main()
{
}
template <class T>
class RpcServer{
public:
void RegisterHandler();
};
struct HandlerInfo{
void (*handler)();
};
template <class T>
void Handle()
{
}
template <class T>
void RpcServer<T>::RegisterHandler(){
HandlerInfo info = {
.handler = Handle<T>
};
}
This compiles on gcc 10. ".member" initialization syntax has been supported by gcc for a long time, but it's only been standardized as of C++20, so other compilers may not support this syntax.
You could, if you wish, declare this to be a pointer to a function that takes an RpcServer<int> as its parameter:
struct HandlerInfo{
void (*handler)(RpcServer<int>);
};
Now, you will be able to initialize it to point to such a function:
HandlerInfo info = {
.handler = Handle<int>
};
HandleInt instantiates a function that takes such a parameter, so the types match exactly.
Or, alternatively, make HandlerInfo itself a matching template:
template <class T>
class RpcServer{
public:
void RegisterHandler();
};
template<class T>
struct HandlerInfo{
void (*handler)(RpcServer<T>);
};
template <class T>
void Handle(RpcServer<T> )
{
}
template <class T>
void RpcServer<T>::RegisterHandler(){
HandlerInfo<T> info = {
.handler = Handle<T>
};
}
int main()
{
RpcServer<int> server;
server.RegisterHandler();
}
(Note -- your code has other syntax errors; if they were fixed it would seem that, at first, the code would compie; but if an attempt was made to instantiate the templates, it would fail due to the type mismatch)
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
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.
I need to specialize a function template in c++.
template<typename T>
void doStuff<T>() {}
To
template<>
void doStuff<DefinedClass>();
and
template<>
void doStuff<DefinedClass2>();
I guess that is not the correct syntax (since it is not compiling). How should I do it?
Also, Since I will have not undefined template parameters in doStuff<DefinedClass>, would it be possible to declare the body in a .cpp?
Note: doStuff will use T wihtin its body to declare a variable.
The primary template doesn't get a second pair of template arguments. Just this:
template <typename T> void doStuff() {}
// ^^^^^^^^^
Only the specializations have both a template <> at the front and a <...> after the name, e.g.:
template <> void doStuff<int>() { }
The correct syntax for the primary template is:
template <typename T>
void doStuff() {}
To define a specialisation, do this:
template <>
void doStuff<DefinedClass>() { /* function body here */ }
I guess that is not the correct syntax (since it is not compiling). How should I do it?
doStuff will use T wihtin its body to declare a variable.
template<typename T>
void doStuff()
{
T t = T(); // declare a T type variable
}
would it be possible to declare the body in a .cpp?
C++ only supports inclusive mode only, you can't compile separately then link later.
From comment, if you want to specialize for int type:
template<>
void doStuff<int>()
{
}
// 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.