0

I am aware that functions can be template arguments. However GCC, Clang and MSVC (compile versions on rextester) do not compile compile when the template is variadic, as shown below:

void Func( int ){}

template<void (*)(int)>
struct Foo{};

template struct Foo<Func>; // Compiles

template<typename>
struct Bar;

template<typename ...Args>
struct Bar<void(*)(Args...)>
{
};

template struct Bar<Func>; // Does NOT compile (why???)

int main()
{
}

MSVC produces the most verbose output and possible explanation (rightly or wrongly) as to why the code does not compile.

source_file.cpp(20): error C2923: 'Bar': 'Func' is not a valid template type argument for parameter 'T'
source_file.cpp(1): note: see declaration of 'Func'
source_file.cpp(20): error C2990: 'Bar': non-class template has already been declared as a class template
source_file.cpp(13): note: see declaration of 'Bar'
source_file.cpp(20): error C2946: explicit instantiation; 'Bar' is not a template-class specialization  

What is the appropriate syntax for passing functions that accept any number of arguments themselves as class template arguments.

Olumide
  • 5,397
  • 10
  • 55
  • 104

1 Answers1

2

Func is not a type, but a function,

you might want:

template struct Bar<decltype(&Func)>;

or maybe

template<typename F, F f> struct Bar;

template <typename ...Args, void(*f)(Args...)>
struct Bar<void(*)(Args...), f>
{
};

and Bar<decltype(&Func), &Func>.

Which can be simplified to (since C++17):

template <auto> struct Bar;

template <typename ...Args, void(*f)(Args...)>
struct Bar<f>
{
};

and Bar<&Func>.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • That was my original solution. I just wondered why `template struct Foo;` compiles. – Olumide Sep 04 '18 at 10:25
  • 1
    @Olumide because `Foo` takes a non-type parameter (of type `void (*)(int)`) – 463035818_is_not_an_ai Sep 04 '18 at 10:28
  • @user463035818 Thanks. BTW, I don't even think my specialization of `Bar` is a match for `template struct Bar`, at least not on GCC and Clang because they complain that `template 'Bar` is undefined. – Olumide Sep 04 '18 at 10:33
  • @Jarod42 Which compiler did you use. The C++17 and C++17 versions of updated answer do not compile on GCC 7.3.0. – Olumide Sep 04 '18 at 10:48
  • 1
    @Olumide: Compile fine [here](http://coliru.stacked-crooked.com/a/4856f7e0aae8b068) with both clang version 5.0.0-3~16.04.1 and g++ (GCC) 8.1.0. – Jarod42 Sep 04 '18 at 11:21
  • @Jarod42 out of curiosity why is is `typename ...Args` allowed to appear before `void(*f)(Args...)` in the specialization bearing in mind this: https://timsong-cpp.github.io/cppwp/n4140/temp.class.spec#8.6 – Olumide Sep 04 '18 at 22:46
  • @Olumide: As I read it, it is in `struct Bar` not in `template **/>` that applies. – Jarod42 Sep 05 '18 at 00:36
  • @Olumide: Look here: https://stackoverflow.com/questions/52175224/how-can-a-template-parameter-pack-have-other-trailing-arguments – Constantinos Glynos Sep 05 '18 at 16:13