C++11 c++;11 std::类函数函子不完整类型

C++11 c++;11 std::类函数函子不完整类型,c++11,C++11,我偶然发现了一件我从上周起就无法通过的事情 具有以下特征: template<typename> struct fx; template<typename R, typename...Args> struct fx<R(Args...)> { virtual R operator()(const Args & ...x) const = 0; }; 模板结构fx; 模板 结构外汇 { 虚拟R运算符()(常量参数&…x)常量=0; }; 这

我偶然发现了一件我从上周起就无法通过的事情

具有以下特征:

template<typename> struct fx;

template<typename R, typename...Args>
struct fx<R(Args...)>
{
    virtual R operator()(const Args & ...x) const = 0;
};
模板结构fx;
模板
结构外汇
{
虚拟R运算符()(常量参数&…x)常量=0;
};
这是:

template<typename> struct fx_err;

// I feel here something is wrong, but I can't figure it out.
template<template<typename> class F, typename R, typename... Args>
struct fx_err< F<R(Args...)> > : fx<R(R,Args...)>
{
    using fx_type = F<R(Args...)>;

    fx_type f;

    R operator ()(const R &y, const Args & ...x) const override
    {
        return y - f(x...);
    }
};
template struct fx\u err;
//我觉得这里有点不对劲,但我想不出来。
模板
结构fx_err:fx
{
使用fx_type=F;
fx_型f;
R运算符()(常量R&y、常量参数和…x)常量重写
{
返回y-f(x…);
}
};
这是:

struct example_fun : fx<int(int,int,int)>
{
    int operator() (const int &a, const int &b, const int &c) const override
    {
        return a * b * c;
    }
};
struct示例\u乐趣:fx
{
int运算符()(常量int&a、常量int&b、常量int&c)常量重写
{
返回a*b*c;
}
};
当我最终尝试像这样使用它时:

fx_err<example_fun> example;
int err = example(24,2,3,4);
fx\u错误示例;
int err=示例(24,2,3,4);
编译器抛出错误:“示例的类型不完整”

只有当我不专门化fx_err,而是使用指向fx_类型函子的指针时,类似的东西才会起作用,但是我需要添加构造函数来获取指针本身,这不是我想要的东西

这很令人沮丧。这个怎么了?有可能实现我的目标吗?有人能帮忙吗

提前谢谢

更新:

这里有一些示例代码供那些愿意尝试此示例的人使用:

fx\u err
与您的部分专业化不匹配,因为
example\u fun
不是
F
的形式。它继承了该表单的一种类型,但这不是同一回事。

在线问题:

fx_err<example_fun> example;
这是一个不完整的类型

您提供的专业化:

// I feel here something is wrong, but I can't figure it out.
template<template<typename> class F, typename R, typename... Args>
struct fx_err< F<R(Args...)> > : fx<R(R,Args...)>
{ ... }

为类模板选择专门化时,不考虑隐式转换。因此,当匹配专门化时,编译器不会将
example\u fun
视为
fx
,并且选择主(未定义)模板而不是其他专门化

要解决此问题,可以在派生类中公开基类的别名:

struct示例\u乐趣:fx
{
使用type=fx;
};
现在在声明站点使用此别名:

fx\u错误示例;
int err=示例(24,2,3,4);
您甚至可以使用宏来避免重复基类名称:

模板结构标记{using type=T;};
#定义基本标签(B)B,公共标签
结构示例\u fun:BASE\u标记(fx){
// ...
};

您的基本问题是模板类型模式匹配与函数重载模板模式匹配不同。继承被忽略,只有传入的类型与模式匹配

因此
struct foo:some_template
在模板类型模式匹配过程中不匹配
some_template
,以确定要使用哪个专门化


这使我们能够将类型作为函数中的值来使用:

template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;
这是去那里的大部分路

接下来,我们需要一些SFINAE助手魔法:

template<class...>struct voider:tag<void>{};
template<class...Ts>using void_t=type_t<voider<Ts...>>;
第二个
class=void
让我们来做FSINAE工作。我们从你的

template<template<class...>class F, class R, class...Args>
struct fx_err< F<R(Args...)>, void > : fx<R(R,Args...)>
{
  using fx_type = F<R(Args...)>;

  fx_type f;

  R operator ()(const R &y, const Args & ...x) const override {
    return y - f(x...);
  }
};
模板
结构fx_err:fx
{
使用fx_type=F;
fx_型f;
R运算符()(常量R&y、常量参数和…x)常量重写{
返回y-f(x…);
}
};
我们也这样做:

template<class T>
struct fx_err< T, void_t<get_template_t<T>>> : fx_err<get_template_t<T>>
{};
模板
结构fx\u err:fx\u err
{};

我认为这应该管用。如果没有,我们只需要添加一个测试,将直接
t
案例从该专门化中排除。

如果可以,请避免使用模板参数。它们增加了比您可能想要的更多的复杂性和更少的灵活性

看起来您正在尝试将
fx
基类的形式与其派生类相匹配。部分专门化需要精确匹配,它不会切片到基类。即使是这样,这个成员也是抽象类类型:

using fx_type = F<R(Args...)>;
fx_type f; // same as fx<R(Args...)> which is abstract

我不知道你为什么认为这个例子可以诚实地编译。因为我认为如果int(int,int,int)减少到一种类型,我可以从fx模板中提取模板参数,所以它应该在fx_err模板中使用额外的“模板化”层,因为这个概念完全类似(我认为是这样的)示例_-fun源于fx,所以编译器识别它应该没有问题,对吧?很明显,我错了,这就是我在这里发布问题的原因。我创建了一个模板,模板参数仍然会让我的眼睛流血。谢谢你,@Potatoswatter,但毕竟,你找到解决这个问题的方法了吗?有时候,经验伴随着我们自己被宠坏的血液而来,所以。。。我会很感激你的建议。为什么你会做那些丑陋的宏观的东西,当你能做丑陋的SFINAE的东西的时候?通过一个具有类似模式的函数将传入的类型反弹到
fx_err
,它将提取基,并让它返回封装在标记中的匹配基的类型,提取它,然后在
fx_err
中使用它。感谢您的建议,@0x499602D2,但您的解决方案不起作用,按照您的建议公开别名后,fx_err中的fx_type f将成为抽象类型,编译器不会看到implementation@Yakk,你能发布一些代码来解释你在说什么吗?不确定我是否理解你的建议:)是的,这似乎是正确的,但是你看到了任何解决方案吗?谢谢你,雅克,但是你的解决方案仍然不起作用,尽管我没有添加你提到的测试。幸运的是,@potatosatter的想法非常有效,所以让我们都从中学习吧!
template<class...>struct voider:tag<void>{};
template<class...Ts>using void_t=type_t<voider<Ts...>>;
template<class,class=void> struct fx_err;
template<template<class...>class F, class R, class...Args>
struct fx_err< F<R(Args...)>, void > : fx<R(R,Args...)>
{
  using fx_type = F<R(Args...)>;

  fx_type f;

  R operator ()(const R &y, const Args & ...x) const override {
    return y - f(x...);
  }
};
template<class T>
struct fx_err< T, void_t<get_template_t<T>>> : fx_err<get_template_t<T>>
{};
using fx_type = F<R(Args...)>;
fx_type f; // same as fx<R(Args...)> which is abstract
template<typename derived, typename base = typename derived::fx>
struct fx_err;

template<typename derived, template<typename> class F, typename R, typename... Args>
struct fx_err< derived, F<R(Args...)> > : F<R(R,Args...)>
template<typename derived, typename base = typename derived::fx>
struct fx_err;

template<typename derived, typename R, typename... Args>
struct fx_err< derived, fx<R(Args...)> > : fx<R(R,Args...)>