Inconsistent output of parameter package with variable templates

I have the following C ++ 11 example, where I have a call function that uses variational patterns to accept and the generic class method is called:

 #include <utility> template <typename T, typename R, typename... Args> R call(R (T::*fn)(Args...), T *t, Args&&... args) { return ((*t).*fn)(std::forward<Args>(args)...); } class Calculator { public: int add(const int& a, const int& b) { return a + b; } }; int main() { Calculator *calculator = new Calculator(); int* a = new int(2); int* b = new int(4); // compiles int res1 = calculator->add(*a, *b); // does not compile! int res2 = call<Calculator>(&Calculator::add,calculator, *a, *b); return 0; } 

As commented in the code, I cannot pass int when the function accepts const int , but in the method of the direction method I can. I get the following compilation error:

 error: no matching function for call to 'call(int (Calculator::*)(const int&, const int&), Calculator*&, int&, int&)' int res2 = call<Calculator>(&Calculator::add,calculator, *a, *b); ^ inconsistent parameter pack deduction with 'const int&' and 'int&' int res2 = call<Calculator>(&Calculator::add,calculator, *a, *b); ^ 

Does the C ++ variational template use more stringent type control than regular execution? I am using g ++ 4.8.1 with C ++ 11.

+6
source share
1 answer

As you call your function template, the package of Args template parameters will be output from two sources:

  • The type of the pointer to the member function is int (Calculator::*)(const int&, const int&)
  • The actual types of arguments ( *a, *b) that you passed for the parameter package to the function are int &, int &

For successful deduction, the result must match exactly. Obviously, they do not.

This is not new or special for variable templates. You have the same problem if you try to make std::max(1, 1.5) - the compiler outputs int from one argument, double from another, and the output is impossible, because there are two conflicts.

The simplest fix probably consists of two packages:

 template <typename T, typename R, typename... Args1, typename... Args2> R call(R (T::*fn)(Args1...), T *t, Args2&&... args) { return ((*t).*fn)(std::forward<Args2>(args)...); } 
+11
source

Source: https://habr.com/ru/post/978330/


All Articles