How to write the test function correctly, so that it can be passed any function f and g as an argument (or a template parameter - not important), with the possibility of calling them with a different type of argument (in the example int, char and long).

http://ideone.com/1aZ8Zu

 #include <iostream> using namespace std; template <typename T> auto f(T x) -> decltype(x*x) { return x * x; } template <typename T> T g(T x) { return x * x; } template <template <class> class F> void test(F f) { auto a = f(32); auto b = f(' '); auto c = f(2000000000L); cout << a << ' ' << b << ' ' << c << endl; } int main() { test(f); test(g); return 0; } 

This code does not compile with messages:

 prog.cpp:15:47: error: variable or field 'test' declared void template <template <class> class F> void test(F f) ^ prog.cpp:15:49: error: missing template arguments before 'f' template <template <class> class F> void test(F f) ^ prog.cpp: In function 'int main()': prog.cpp:26:8: error: 'test' was not declared in this scope test(f); ^ 
  • A related answer that did not help me. - Qwertiy
  • Of course it did not help, the function is not a class. - Abyx

3 answers 3

I can recommend a workaround in a certain sense, but in a definite way a direct way. In C ++ 14 (and you clearly have this tag), lambdas can also be templates.

 auto f = [](auto x){ cout << x << endl; return x*x; }; template<typename F> void test(F f) { auto a = f(32); auto b = f(' '); auto c = f(2000000000ull); cout << a << ' ' << b << ' ' << c << endl; } int main() { test(f); return 0; } 

It is called f as a pattern (different for different arguments).

Yes, this is not an absolutely strict and exact answer to the question asked, but - the template in the template is called :)

You can use lambda and as a level of indirection:

 template <typename T> T g_(T x) { return x * x * x; } auto g = [](auto x){ cout << typeid(x).name() << endl; return g_(x); }; template<typename F> void test(F f) { auto a = f(32); auto b = f(' '); auto c = f(2000000000ull); cout << a << ' ' << b << ' ' << c << endl; } int main() { test(g); return 0; } 

An example on ideone: http://ideone.com/kfUWtx

    A bit of theory.

    In order to be able to call f(42) and f(42L) at the same time - the variable f must be of the type for which the template operator () is defined:

     struct F { template <typename T> void operator () (T value); }; void test(F f); // работает 

    If you move the template to another location, you will not be able to instantiate F :

     template <typename T> struct F { void operator () (T value); }; void test(F f); // ошибка компиляции: F - это шаблон типа, а не тип 

    The problem with functions is that the reference to the template function is more similar in its properties to the second form of the record than to the first.

    As already written by @Harry , to implicitly create a structure of the first type, you can use lyabmdy

     auto g = [](auto x){ return x*x; }; template<typename F> test(F f); // сюда можно передать переменную g 
    • It is not necessary to have a template operator() , you can also have a constructor . - αλεχολυτ
    • @alexolut I consider f - as a variable of some type, not a type in itself. It is obvious that a type with a template constructor cannot be transferred to a function by value. - Pavel Mayorov
    • Then, IMHO, it makes sense to add after одновременно : из функции, которая принимает переменную f . To offer was self-sufficient. Although, I agree that the context here must also be borne in mind. - αλεχολυτ
    • @alexolut, the use of a constructor, in such a context, contradicts its semantics. In C ++, it is common to use operator()() for similar purposes. - ixSci
    • @ixSci I proceeded from the requirement of self-sufficiency of the sentence, therefore I gave such an example. - αλεχολυτ

    It is impossible, in the form that you want. You have two sample functions test and f , which occur in the same expression, and in which the type of the argument must be inferred from the arguments passed. What can the compiler infer from this test(f) line? Nothing, because There is no clarifying information specifying what version to instantiate.

    • I am satisfied with the test<f>() , but it also fails :) - Qwertiy
    • @Qwertiy, you have not changed or added anything - neither f nor test here have become specific. - ixSci