17

By using template template parameters one can pass to a class a templated class without specifying types on its parameters. I was wondering is there a way to pass into a template template parameter a templated signature of a function to be able to specialize which variant of the function is to be considered forward.

To be clear - I know I cannot do that:

template <class T>
void foo() { /*...*/ }

template <template <class...> class FooType>
struct Foo { /*...*/ };

int main() {
    Foo<decltype(foo)> f;
}

But somehow I would like to be able to pass templated signature of function to Foo. Is it even possible?

W.F.
  • 13,888
  • 2
  • 34
  • 81

5 Answers5

8

I couldn't believe that this is not possible so I searched a bit and found a way to do exactly what I wanted. I used templated using with a syntax:

template <template<class... Args> class FooType>
struct Foo {
   FooType<int> ft;
};

template <class Res, class... Args>
using FooSignature = Res(*)(Args...);

int foo() {
   return 1;
}

int main() {
   Foo<FooSignature> f;
   f.ft = foo;
}

This however still leaves the question how can this be possible since the standard states something opposite.

W.F.
  • 13,888
  • 2
  • 34
  • 81
7

In the example below one has a template template parameter that accepts the preferred signature for the function.
Because of the specialization and the lack of a body for the template class, only types for callables are accepted.
It is a generalization of what the OP actually asked:

#include<cassert>

template<typename F>
struct S;

template<typename R, typename... Args>
struct S<R(Args...)> {
    using type = R(*)(Args...);
};

template<template<typename> class F>
struct T {
    typename F<void(int)>::type ft;
    typename F<double(double, double)>::type gt;
};

void f(int) { }
double g(double x, double y) { return x+y; }

int main() {
    T<S> t;
    t.ft = f;
    t.gt = g;
    t.ft(42);
    auto v = t.gt(1., 1.);
    assert(v == 2.);
}
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • 1
    Yes the `using` does the trick here. This approach seems to be even cleaner than templated `using`... – W.F. Apr 29 '16 at 20:53
  • Can I ask you what you are using it for? Just curiosity... I can't see an use for `T` where I can't use simply `S`. – skypjack Apr 29 '16 at 21:18
  • Of course, the question rose from another archive question: http://stackoverflow.com/questions/36655835/better-pattern-for-partial-specialization-disambiguation-precedence-chain/36657353#36657353 I wanted to propose a general tag that would be able to accept both template template class and function with a given signature... Then I realized that this is not a trivial task... :) – W.F. Apr 29 '16 at 21:53
4

As can be seen in this answer

Template of function pointer is illegal in C++

The C++ Standard says in $14/1,

A template defines a family of classes or functions.

Further quoting from the linked answer:

Please note that it does NOT say "A template defines a family of classes, functions or function pointers"

However, you can pass concrete function pointers, and specialise on their signature:

#include <iostream>

template <class T>
void foo(T) { }

template <typename>
struct Foo;

template<typename T> 
struct Foo<void(T)> 
{
    void cb() { std::cout << "T\n"; }
};

template<> 
struct Foo<void(int)> 
{
    void cb() { std::cout << "int\n"; }
};

template<> 
struct Foo<void(double)> 
{
    void cb() { std::cout << "double\n"; }
};

int main() 
{
    Foo<decltype(foo<int   >)>().cb(); // outputs 'int'
    Foo<decltype(foo<double>)>().cb(); // outputs 'double'
    Foo<decltype(foo<char  >)>().cb(); // outputs 'T'
    return 0;
}
Community
  • 1
  • 1
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
3

template of template is still a template.

template <class T>
void foo() { /*...*/ }

template <typename T>
struct Foo { /*...*/ };

int main() {
    Foo<decltype(foo<int>)> f;
}
0xFFFFFFFF
  • 852
  • 5
  • 9
2

You cannot pass a function template as an argument. What you can do is wrap a function template in a generate lambda taking a tag parameter:

template <class T> struct tag_t { using type = T; };

template <class T>
void foo() { ... }

template <class F>
void call_func_with(F f) {
    f(tag_t<int>{} );
    f(tag_t<double>{} );
}

call_with_func([](auto tag) { foo<decltype(tag)::type>(); } );

Here, f(tag_t<X>{} ) ends up calling foo<X>(), as desired.

Barry
  • 286,269
  • 29
  • 621
  • 977