In the following class I try to specialize a type-erased function to an empty type for the case of default initialization. However, this yields the following error: explicit specialization in non-namespace scope
. Now I've done my research and learned that gcc for some reason doesn't allow full template specialization in class scope, so consequently I would have to pull it out of the class and put it in namespace scope. However this leaves me with an even bigger misery bc as you can see the class template parameters are used to forward arguments to an external function. So I would have to templatize on that as well. but then again, I can not partially specialize function templates for the cases that Args... is a template and specialized for empty_t
only. How do I resolve this elegantly?
#include <utility>
#include <cstdio>
template <typename... Ts>
void myfunc(Ts... args)
{
printf("Do something!\n");
}
template <typename R, typename... Args>
struct entity;
template <typename R, typename... Args>
struct entity<R(Args...)>
{
using fn_invoke_t = R(*)(void*);
struct empty_t{};
template <typename T>
static R fn_invoke(Args&&... args) {
return myfunc(args...);
}
template <>
static R fn_invoke<empty_t>(Args&&... args) {
return myfunc(args...);
}
entity()
: fn_invoke_(reinterpret_cast<fn_invoke_t>(fn_invoke<empty_t>))
{ }
template <typename T>
entity(T obj)
: fn_invoke_( reinterpret_cast<fn_invoke_t>(fn_invoke<T>) )
{ }
fn_invoke_t fn_invoke_;
};
int main()
{
entity<void()> hello = [](){ printf("Hello World!\n"); };
// hello();
}
Error:
<source>:27:15: error: explicit specialization in non-namespace scope 'struct entity<R(Args ...)>'
27 | template <>
| ^
<source>:28:14: error: template-id 'fn_invoke<entity<R(Args ...)>::empty_t>' in declaration of primary template
28 | static R fn_invoke<empty_t>(Args&&... args) {
CodePudding user response:
You can change to function template overloading instead. E.g.
template <typename T>
static std::enable_if_t<!std::is_same_v<T, empty_t>, R>
fn_invoke(Args&&... args) {
return myfunc(args...);
}
template <typename T>
static std::enable_if_t<std::is_same_v<T, empty_t>, R>
fn_invoke(Args&&... args) {
return myfunc(args...);
}
CodePudding user response:
You can also add an intermediate class template and fully specialize it (your call if static function or operator() is to be used):
struct empty_t{};
template<typename T, typename R, typename ...Args>
struct detail
{
static R call(Args&&... args)
{
my_func(args...);
}
};
template<typename R, typename ...Args>
struct detail<empty_t, R, Args...>
{
static R call(Args&&... args)
{
my_func2(args...);
}
};
Then inside entity class:
template <typename T>
static R fn_invoke(Args&&... args) {
return detail<T, R, Args...>::call(args...);
}