Home > OS >  error: explicit specialization in non-namespace scope
error: explicit specialization in non-namespace scope

Time:12-14

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?

struct entity; template struct entity { using fn_invoke_t = R(*)(void*); struct empty_t{}; template static R fn_invoke(Args&&... args) { return myfunc(args...); } template <> static R fn_invoke(Args&&... args) { return myfunc(args...); } entity() : fn_invoke_(reinterpret_cast(fn_invoke)) { } template entity(T obj) : fn_invoke_( reinterpret_cast(fn_invoke) ) { } fn_invoke_t fn_invoke_; }; int main() { entity hello = [](){ printf("Hello World!!\n"); }; // hello(); }'),l:'5',n:'0',o:'C++ source #1',t:'0')),k:48.804757760371345,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((g:!((h:compiler,i:(compiler:g122,deviceViewOpen:'1',filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'0',intel:'0',libraryCode:'0',trim:'1'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c++,libs:!(),options:'-Wall -Os --std=gnu++20',selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:' x86-64 gcc 12.2 (Editor #1)',t:'0')),header:(),l:'4',m:41.3677130044843,n:'0',o:'',s:0,t:'0'),(g:!((h:output,i:(compilerName:'x86-64 gcc 12.2',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output of x86-64 gcc 12.2 (Compiler #1)',t:'0')),k:50,l:'4',m:58.632286995515706,n:'0',o:'',s:0,t:'0')),k:51.19524223962866,l:'3',n:'0',o:'',t:'0')),l:'2',n:'0',o:'',t:'0')),version:4" rel="nofollow noreferrer">Demo

#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...);
}

LIVE

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...);
    }

https://godbolt.org/z/ehYYvnofE

  • Related