错误:在非命名空间范围内显式特化



在下面的类中,我尝试将类型擦除函数专门化为默认初始化的空类型。然而,这产生了下面的error: explicit specialization in non-namespace scope。现在我已经做了研究,了解到由于某种原因,gcc不允许在类范围内进行完整的模板专门化,因此我必须将其从类中取出,并将其放在名称空间范围内。然而,这给我留下了更大的痛苦,因为你可以看到类模板形参是用来将参数转发给外部函数的。所以我也要以此为模板。但话又说回来,我不能部分特化函数模板的情况下,Args…是专用于empty_t的模板。我该如何优雅地解决这个问题?

演示
#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();
}

错误:

<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) {

一种变体可能是完全放弃专门化,而在模板中使用if constexpr,例如:

if constexpr(std::is_same_v<T, SpecificType>)
{
/* special code */
}
else
{
/* general code */
}

如果需要,您可以删除类型限定符,如std::remove_cv_t<std::remove_reference_t<T>>或c++ 20std::remove_cvref_t<T>,以便constvolatile类型或引用被同等对待。

在你的例子中,这将导致:

if constexpr(std::is_same_v<T, empty_t>)
{
return myfunc(args...);
}
else
{
return myfunc(args...);
}

godbolt的演示。

你可以改成函数模板重载。例如

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

生活

您还可以添加一个中间阶段:"helper"类模板并在entity类之外对其进行专门化(如果要使用静态函数或operator(),则调用):

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

这种方法可以规避部分专门化函数的不可能性。

然后在实体类内部:


template <typename T>
static R fn_invoke(Args&&... args) {
return detail<T, R, Args...>::call(args...);
}

https://godbolt.org/z/ehYYvnofE

相关内容

  • 没有找到相关文章

最新更新