【问题标题】:Is there a generic way to adapt a function template to be a polymorphic function object?是否有一种通用方法可以将函数模板改编为多态函数对象?
【发布时间】:2011-10-25 09:46:37
【问题描述】:

我有一些函数模板,例如

template <typename T>
void foo(T);

template <typename T>
void bar(T);

// others

我需要将每一个传递给一个算法,该算法将以各种类型调用它,例如

template <typename F>
void some_algorithm(F f)
{
    // call f with argument of type int
    // call f with argument of type SomeClass
    // etc.
}

我无法在未实例化的情况下传入我的函数模板,但我也无法使用任何特定类型对其进行实例化,因为some_algorithm 需要使用几种不同类型的参数来调用它。

我可以将我的函数模板调整为多态函数对象,例如

struct foo_polymorphic
{
    template <typename T>
    void operator()(T t)
    {
        foo(t);
    }
};

然后将其作为some_algorithm(foo_polymorphic()) 传递。但这需要为我的每个函数模板编写一个单独的适配器。

是否有一种通用方法可以将函数模板调整为多态函数对象,即我可以为我需要调整的每个函数模板重复使用的某种机制,而不必为每个单独声明一些东西?

【问题讨论】:

  • @Seth:因为这对语言没有意义。
  • Non-type template parameters must be of integral, enumeration, pointer, reference, or pointer to member type, and must be constant at compile time. 你不能传递一个未实例化的函数名,主要是因为你不能得到一个指向它的指针。您将不得不使用其他技巧。
  • foo_polymorphic 可以用宏生成以简化任务。
  • 我要说的是,没有宏就无法做到这一点。在 C++0x 中如果有多态 lambdas,您只需这样做:some_algorithm([](auto x){ foo(x);});。那么,从这一点来看,我认为您的问题与其他“我如何模拟 lambdas”问题没有什么不同,只是在您的情况下,您想要更多增强的 lambdas。与模拟 lambda 的情况一样:手动。 ://
  • 想提一下,上面的结构可能有问题,因为它不完美地将 t 转发到 foo。

标签: c++ templates static-polymorphism function-template


【解决方案1】:

为什么不能使用模板模板参数?你说你不能在未经实例化的情况下传递你的模板,但我不确定你以前是否听说过这个,告诉我你是否听说过,但它不起作用。

我不知道你的代码结构是什么样的,但你能做类似的事情

我知道这行得通,但不知道是不是你想要的:

template<typename T>
T some_algorithm(T data) { return T(); } // just returning nothing for example

template<typename T, T(*Something)(T)>
class FuncClass {
public:
    T run(T data) { return Something(data); }
};

template<typename T, typename Functor>
void apply_algorithm(T data) {
    Functor F;
    F.run(data);
}

int main() {
    int mydata = 4;
    apply_algorithm<int, FuncClass<int, some_algorithm<int> > >(mydata);

    cin.get();
}

【讨论】:

  • 如果Algorithm 是类类型,那很好。函数不是。
  • @GMan 你能再看看它是否有意义?
  • @GMan:这很有趣——函数模板可以绑定到任何东西吗?
  • @Seth:您所做的只是指定实例化myalgo 的哪些版本(在本例中为int)。请注意,他的手动版本不需要知道函数名称以外的任何内容,因为扣除处理了其余部分。需要指定模板参数无法达到目的。
【解决方案2】:

问题的简写版被赋予重载名称f,如何简洁地写一个对象ff使得ff(a0, a1, a2, ...)最终调用f(a0, a1, a2, ...)

多态函子,你如何指出自己,是通常的解决方案。但它必须定义得不合时宜(因为它有一个模板成员),所以我认为这对于我的回答来说不够简洁。

目前 lambda 表达式产生一个单态函子,所以它们很接近但并不完全在那里。

// set of functions overloaded on int and double
void f(int);
void f(double);

auto ff = [](int i) { return f(i); };

正如 GMan 在 cmets 中指出的那样,多态 lambda 将(应该?)成为简洁地内联编写多态函子的解决方案。

同时,可以编写一个make_overload 帮助器,将多个函子合二为一,这样

auto ff = make_overload(
    [](int arg0) { return f(arg0); }
    , [](double arg0) { return f(arg0); } );

将“捕获”整个重载集。也许 Boost.Preprocessor 宏在这里可以提供帮助,以便内联使用 auto ff = POLYMORPHIC_LAMBDA( 1, (int)(double), { return f(arg0); } );。但是,我怀疑存在数量限制(因此是第一个宏参数),这与通常的离线手写多态函子解决方案不同;所以这对例如没有帮助可变参数函数模板。

【讨论】:

  • 我希望单个函数模板的不太通用的情况可能比重载名称的通用情况更容易。我猜不是……
  • 有趣!如果我们能以某种方式获取函数需要调用的类型的mpl::vector,我们可以编写POLYMORPHIC_LAMBDA(f, mplvec) 形式的宏吗?
  • @HighCommander4 它们有相似之处:名称foo(来自您的问题)不能作为函数参数(到函数模板)或作为非类型模板参数传递而不会丢失多态性。这是问题的根源。
  • @HighCommander4 一个有趣的想法。然而,宏不能操作 Boost.MPL 序列;如果可以,那么from_sequence&lt;Sequence&gt;::make_overload()(f, f, f, f, f);(假设这里有 5 个重载)将解决问题。这就是为什么在我的示例中使用 Boost.PP 序列的原因:宏必须插入名称(这是唯一具有多态行为的东西)与重载一样多次。它仍然比我插入整个身体的提议更精细,并且它处理启动的arity! (请注意,在 C++ 聊天中欢迎这种扩展讨论。)
  • (@Luc:我不同意,尽管网站所有者不这么认为。你的讨论完全属于这里,就在它开始的地方。这样读者以后不必去搜索一些聊天室才发现它已被删除。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-17
  • 1970-01-01
  • 2017-08-18
  • 2010-11-22
  • 1970-01-01
  • 2021-08-30
相关资源
最近更新 更多