Reputation: 1
I hava the following template class like a function wrapper:
using MethodId = std::uint16_t;
template <typename Func>
class BaseMethod
{
public:
BaseMethod(const Func &func, std::uint16_t method_id) : _function(func), _method_id(method_id) {}
template <typename... Args>
auto operator()(Args... args) -> decltype(_function(std::forward<Args>(args)...))
{
return _function(std::forward<Args>(args)...);
}
template <typename... Args>
auto invoke(Args... args) -> decltype(_function(std::forward<Args>(args)...))
{
return _function(std::forward<Args>(args)...);
}
private:
Func _function;
MethodId _method_id;
};
with this class template, I can use like this:
int adder(int x, int y){return x+y;}
BaseMethod<int(*)(int, int)> foo_tempalte(adder, 0);
but I also want to support usage like this:
BaseMethod<int, int, int> bar_tempalte(adder, 0);
So I add a partial specification version:
template <typename Ret, typename... Args>
class BaseMethod<Ret (*)(Args...)>
{
public:
BaseMethod(Ret (*func)(Args...), std::uint16_t method_id) : _function(func), _method_id(method_id)
{
}
Ret operator()(Args... args)
{
return _function(std::forward<Args>(args)...);
}
Ret invoke(Args... args)
{
return _function(std::forward<Args>(args)...);
}
private:
Ret (*_function)(Args...);
std::uint16_t _method_id;
};
but when I called BaseMethod<int, int, int> bar_tempalte(adder, 0);
the ide gave me error: too many arguments for class template "BaseMethod"
I wonder what is wrong with my code? Thanks!
Upvotes: 0
Views: 55
Reputation: 490018
Unless you need to support older compilers (pre-C++17) or really, truly, absolutely need to force the user to explicitly pass template arguments, I'd just let the compiler deduce the function type from argument:
#include <utility>
#include <cstdint>
#include <iostream>
using MethodId = uint16_t;
template <typename Func>
class BaseMethod
{
public:
BaseMethod(Func func, MethodId method_id) : _function(func), _method_id(method_id) {}
template <typename... Args>
auto operator()(Args... args)
{
return _function(std::forward<Args>(args)...);
}
// leaving out `invoke` since it's basically the same as operator()
private:
Func _function;
MethodId _method_id;
};
int adder(int x, int y){return x+y;}
int add3(int x, int y, int z) { return x + y + z; }
int main() {
// your original code still works:
BaseMethod<int (*)(int, int)> foo_template(adder, 0);
std::cout << foo_template(5, 6) << "\n";
// But it's easier to let the compiler deduce the type:
BaseMethod bar_template(adder, 1);
std::cout << bar_template(1, 2) << "\n";
BaseMethod baz_template(add3, 2);
std::cout << baz_template(1, 2, 3) << "\n";
}
Upvotes: 0