I have the following functions in class "C"
class C
{
template<typename T> void Func1(int x);
template<typename T> void Func2(int x);
};
template<typename T> void C::Func1(int x)
{
T a(x);
}
template<typename T> void C::Func2(int x)
{
T a(x);
}
The functions uses templates only in the implementation. The signature does not contain template parameters.
Is it possible to define pointers to such template functions?
I tried the following definition but it results compilation error.
typedef template<typename T> void (СSomeClass::*TFuncPtr)(int);
Once instantiated, a member function template is just a normal member function, so you can use a normal member function pointer (best typedef'd like below):
typedef void (C::*mem_fun_ptr)(int);
mem_fun_ptr p = &C::Func1<Bar>;
// IMPORTANT -- ^^^^^
The underlined part is the important part. You can't make a pointer to a function template, but you can make a pointer to an instantiated function template.
do you want only a pointer to a function?
that's simple:
class C
{
public:
template<typename T> void Func1(int x);
};
typedef void (C::*TFuncPtr)(int);
int main()
{
TFuncPtr ptr = &C::Func1<int>;
}
if you want something else could you show an example of using the pointer you want?
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)
Is there a concise way to point to all instances of a templated function without using macros?
I have several templated functions that I want to test across a variety of types:
template<typename T>
void function1() {
return;
}
template<typename T>
void function2() {
return;
}
template<typename T>
void function3() {
return;
}
I can do this with a macro:
#define TEST_ACROSS_TYPES(fn) \
fn<int>(); \
fn<bool>(); \
fn<char>(); \
fn<double>(); \
TEST_ACROSS_TYPES(function1);
TEST_ACROSS_TYPES(function2);
But, (1) Macros are ugly and hard for others to follow, and (2) I'm using CATCH, which doesn't play nice when using macros to set up test cases.
Is there a way to do something like this:
void testAcrossTypes(SomeType f) {
f<int> ();
f<bool> ();
f<char> ();
f<double> ();
}
which seems much cleaner, except for the problem of defining SomeType. This question (How to define typedef of function pointer which has template arguments) explains how to define a pointer to a templated function; but, requires that the template arguments be specified.
For clarification: Imagine function1, function2, and function3 each test a different templated function. Each function needs to be tested for int, byte, char, double, etc. I want to avoid having to explicitly set up many (i.e. num_functions * num_types) tests for each function. Instead, I want to have a single method that points to the test function (function1, function2, etc.) and runs it for each template type, thus consolidating
function1<int>();
function1<byte>();
function1<char>();
function1<double();
...
function2<int>();
function2<byte>();
function2<char>();
function2<double();
...
function3<int>();
function3<byte>();
function3<char>();
function3<double();
...
into just one call per test function
testAcrossTypes(function1);
testAcrossTypes(function2);
testAcrossTypes(function3);
What you are trying to accomplish with
void testAcrossTypes(SomeType f) {
f<int> ();
f<bool> ();
f<char> ();
f<double> ();
}
would be possible if SomeType could be a template template argument. However, the standard does not allow function templates as template template argument.
From the C++11 Standard:
14.3.3 Template template arguments
1 A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.
Your best option is to use functors instead of functions. Example:
template<typename T>
struct function1
{
void operator()() {
return;
}
};
template<typename T>
struct function2
{
void operator()() {
return;
}
};
template < template <typename> class F>
void testAcrossTypes() {
F<int>()();
F<bool>()();
F<char>()();
F<double>()();
}
int main()
{
testAcrossTypes<function1>();
testAcrossTypes<function2>();
}
You can accomplish it by means of a type-erased functor, like the one in the following example:
#include<vector>
template<typename T>
void function1() { }
template<typename T>
void function2() { }
template<typename T>
void function3() { }
struct Test {
template<typename T>
static void proto() {
function1<T>();
function2<T>();
function3<T>();
}
void operator()() {
for(auto &f: vec) f();
}
template<typename... T>
static Test create() {
Test test;
int arr[] = { (test.vec.emplace_back(&proto<T>), 0)... };
(void)arr;
return test;
}
using func = void(*)(void);
std::vector<func> vec;
};
void testAcrossTypes(Test test) {
test();
}
int main() {
testAcrossTypes(Test::create<int, bool, char, double>());
}
It's easy to modify in both cases:
New functions require to be added to the proto static member method and that's all
Adding a new type is a matter of using it when call create, as shown in the above example
The functor will keep in charge of creating the N*M calls to be executed.
Moreover, you don't need to move your functions in a bunch of structs to be able to use them.
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();
}
I only have an hpp file for a school assignment in C++ (I am not allowed to add a cpp file, declaration and implementation should be both written in the file).
I wrote this code inside it:
template<class T>
class Matrix
{
void foo()
{
//do something for a T variable.
}
};
I would like to add another foo method, but this foo() will be specialized for only an <int>.
I have read in some places that I need to declare a new specialization class for this to work. But what I want is that the specialized foo will lie just beneath the original foo, so it will look like this:
template<class T>
class Matrix
{
void foo(T x)
{
//do something for a T variable.
}
template<> void foo<int>(int x)
{
//do something for an int variable.
}
};
Why am I getting an error for this syntax ("expected unqualified-id before '<' token")?
Why isn't this possible?
How can I fix this without declaring a new specialized class?
Thanks
foo isn't a template. It's a member function of a template. Thus foo<int> is meaningless. (Also, explicit specializations must be declared at namespace scope.)
You can explicitly specialize a member function of a particular implicit instantiation of a class template:
template<class T>
class Matrix
{
void foo(T x)
{
//do something for a T variable.
}
};
// must mark this inline to avoid ODR violations
// when it's defined in a header
template<> inline void Matrix<int>::foo(int x)
{
//do something for an int variable.
}
You need to define the original foo method as a template, and actually there is no need for your class to be a template, only the method:
class Matrix
{
template<typename T> void foo(T x)
{
//do something for a T variable.
}
template<> void foo<int>(int x)
{
//do something for an int variable.
}
};
UPDATE: The code works only in Visual Studio. Here is a code that should work elsewhere too:
class Matrix
{
template<typename T> void foo(T x)
{
//do something for a T variable.
}
};
template<> void Matrix::foo<int>(int x)
{
//do something for an int variable.
}
I seem to be unable to use multiple layers of templates in the following manner,
template <typename T>
template <T value>
void printValueAsInteger()
{
printf("value as integer is %i\n", (int) value);
}
so that it could be called as:
printValueAsInteger<123>();
It results in the following error message: too many template-parameter-lists.
It works if I use template <typename T, T value> with printValueAsInteger<int, 123>(), but that requires me to explicitly specify the type. How can I make it so that printValueAsInteger<123>() prints value as integer is 123?
edit:
I'll be more specific in what I need this for. My goal is to pass a member function as a function pointer, and I thought of wrapping it using templates:
template <typename T>
template <T* instance, void (T::*method)()>
void wrappedMethod()
{
(instance->*method)();
}
void callFunction(void (*function)())
{
(*function)();
}
and then pass it like this:
Base *instance = new Derived;
callFunction(&wrappedFunction<instance, Base::method>);
edit:
Err, I just realised that I probably shouldn't (and can't) use a runtime-defined variable as a template argument. I'm now trying to work around it using a class instantiated with the otherwise template arguments and creating a template function which uses that class. Or something like that. Nope, doesn't work.
Note that I cannot change the signature of callFunction, as it's part of a third party API.
At last!
I put the following in a header,
class Callable
{
public:
virtual ~Callable() { }
virtual void call() { }
};
typedef void (*functionPtr)();
extern unsigned nextMethodId;
extern functionPtr wrappedMethods[];
extern Callable *boundMethods[];
template <unsigned I>
class MethodWrapper
{
public:
static void function();
};
template <typename T>
class Method : public Callable
{
public:
Method(T* instance, void (T::*method)());
virtual void call();
private:
T* instance;
void (T::*method)();
};
template <typename T>
Method<T>::Method(T* instance, void (T::*method)())
: instance(instance), method(method) {
}
template <typename T>
void Method<T>::call()
{
if (instance && method)
(instance->*method)();
}
template <typename T>
static functionPtr bindMethod(T* instance, void (T::*method)())
{
boundMethods[nextMethodId] = new Method<T>(instance, method);
return (void (*)()) wrappedMethods[nextMethodId++];
}
and this in a source file:
#include "<insert header name here>.h"
unsigned nextMethodId = 0;
functionPtr wrappedMethods[] = {
&MethodWrapper<0>::function,
&MethodWrapper<1>::function,
&MethodWrapper<2>::function
};
Callable *boundMethods[sizeof(wrappedMethods) / sizeof(functionPtr)];
template <unsigned I>
void MethodWrapper<I>::function()
{
boundMethods[I]->call();
}
and I could use it like this:
Base *instance = new Derived;
void (*function)() = bindMethod(instance, &Base::method);
callFunction(function);
It successfully calls the derived instance's version of the method. Sadly, the amount of methods you are allowed to bind is fixed (three in this example), but it's easily extendable.
A simple transform is having the runtime value be an argument to the constructor of a functor that holds the instance pointer and the pointer to member function. The syntax at the place of use will change from:
Base *instance = new Derived;
callFunction(&wrappedFunction<instance, Base::method>);
To:
callFunction( WrappedFunction<Base,&Base::method>( instance ) );
The implementation of the WrappedFunction type is actually simple, so I leave it as an exercise. Note that a major change in this approach is that the argument to callFunction becomes a functor, and not a function pointer.
In C++11 (or with boost) the simplest way would be not coding anything and just use the available resources. Change the signature of callFunction to:
void callFunction( function<void ()> f );
And use bind to place the call:
callFunction( bind( &Base::method, instance ) );
For your first example, you can specify int as the type of template parameter:
template <int I>
void printValueAsInteger()
{
printf("value as integer is %i\n", I);
}
For your edit, you cannot use runtime-defined variables as you have already mentioned because templates are used at compile-time. Using std::bind and std::function would make it simple:
void callFunction(std::function<void()> f)
{
f();
}
Base *instance = new Derived;
callFunction(std::bind(&Base::method, instance));
After Comment
The only way I can think of is to make your member function static:
callFunction(&Base::method); // Okay if the method is declared static
Or use a global wrapper function with a global instance:
Base *instance = new Derived; // Global
void wrapperFunction()
{
instance->method();
}
callFunction(wrapperFunction);