Sébastien Chapuis
Sébastien Chapuis

Reputation: 185

GCC failed with variadic template and pointer to member function

#include <memory>
#include <iostream>

class           Manager
{
public:
  Manager() {}
  virtual ~Manager() {}

  int funcA(std::shared_ptr<int> a, float b) { return *a + b; }
  int funcA(std::shared_ptr<double> a) { return *a; }
};

template <typename T, typename... Args>
auto resolver(int (Manager::*func)(std::shared_ptr<T>, Args...)) -> decltype(func) {
  return func;
}                                                                                                                                  

int main(int, char **)
{
  Manager m;
  Manager *ptr = &m;

  auto var = std::make_shared<int>(1);

  int result = (ptr->*resolver<int>(&Manager::funcA))(var, 2.0);

  std::cout << result << std::endl;

  return 0;
}

This code fail to compile with gcc but is fine with clang. (gcc 5.3.1 and 6.0.0 20151220).

Do you know if there is any solution to make it compile with gcc ? I tried with template specialization and explicit instantiation.

EDIT: gcc gives the following error:

test > g++ -std=c++11 test.cpp 
test.cpp: In function 'int main(int, char**)':
test.cpp:29:52: error: no matching function for call to 'resolver(<unresolved overloaded function type>)'
   int result = (ptr->*resolver<int>(&Manager::funcA))(var, 2.0);
                                                    ^
test.cpp:15:6: note: candidate: template<class T, class ... Args> decltype (func) resolver(int (Manager::*)(std::shared_ptr<_Tp1>, Args ...))
 auto resolver(int (Manager::*func)(std::shared_ptr<T>, Args...)) -> decltype(func) {
      ^
test.cpp:15:6: note:   template argument deduction/substitution failed:
test.cpp:29:52: note:   mismatched types 'std::shared_ptr<int>' and 'std::shared_ptr<double>'
   int result = (ptr->*resolver<int>(&Manager::funcA))(var, 2.0);
                                                    ^
test.cpp:29:52: note:   could not resolve address from overloaded function '& Manager::funcA'
test > 

Upvotes: 3

Views: 270

Answers (1)

Jarod42
Jarod42

Reputation: 217810

As a workaround, you may use

template <typename T>
struct resolver
{
    template <typename... Args>
    auto operator ()(int (Manager::*func)(std::shared_ptr<T>, Args...)) -> decltype(func) {
      return func;
    }
};

With call like

(ptr->*resolver<int>{}(&Manager::funcA))(var, 2.0);

Note the extra {} to call constructor.

Upvotes: 1

Related Questions