C++ Build error: expected type-specifier before [Variadic templates] class

416 views Asked by At

Here is my code:

#include <stdio.h>
#include <utility>
#include <tuple>

template <typename Obj, typename Method, typename Args, size_t... Ns>
inline void DispatchToMethodImpl(const Obj& obj, Method method, Args&& args,
                                 std::index_sequence<Ns...>) {
  (obj->*method)(std::get<Ns>(std::forward<Args>(args))...);
}

template <typename Obj, typename Method, typename Args>
inline void DispatchToMethod(const Obj& obj, Method method, Args&& args) {
  constexpr size_t size = std::tuple_size<std::decay_t<Args>>::value;
  DispatchToMethodImpl(obj, method, std::forward<Args>(args),
                       std::make_index_sequence<size>());
}

class TaskEventBase {
 public:
  virtual void Run() = 0;
};

template <typename Obj, typename Method, typename Args>
class TaskEvent : public TaskEventBase {
 public:
  TaskEvent(Obj* obj, Method method, Args&& args) {
    obj_ = obj;
    method_ = method;
    args_ = std::forward<Args>(args);
  }

  void Run() override { DispatchToMethod(obj_, method_, args_); }

 private:
  Obj* obj_;
  Method method_;
  Args args_;
};


int main() {
  printf("event loop test start\n");
  struct Foo {
    int x;
    int y;

    int Add(int a, int b) {
      printf("res is %d\n", a + b);
      return a + b;
    }
  };

  Foo foo;
  DispatchToMethod(&foo, &Foo::Add, std::make_tuple(1, 2));
  auto e = new TaskEvent(&foo, &Foo::Add, std::make_tuple(1, 2));
  printf("event loop test end\n");

  return 0;
}

Try build with: g++ -g -Wall -std=c++14 -o a test_template_args.cc

Then I get the following error:

test_template_args.cc:70:16: error: expected type-specifier before ‘TaskEvent’                                                                                   
   auto e = new TaskEvent(&foo, &Foo::Add, std::make_tuple(1, 2));      

I don't understand why DispatchToMethod function template works:

DispatchToMethod(&foo, &Foo::Add, std::make_tuple(1, 2));

But TaskEvent class template doesn't work:

auto e = new TaskEvent(&foo, &Foo::Add, std::make_tuple(1, 2));
1

There are 1 answers

0
rafix07 On

Since C++17 your code works due to CTAD.

Until C++14, the code doesn't work because constructor of TaskEvent is non template function, so class template parameters cannot be deduced from the call parameters of TaskEvent constructor, contrary to DispatchToMethod which is template function - all Obj, Method and Args are deducible from passed arguments of function invocation.

You can explicitly provide template parameters via template arguments list:

  auto e = new TaskEvent< Foo,int(Foo::*)(int,int),std::tuple<int,int> >
                    (&foo, &Foo::Add, std::make_tuple(1, 2));