2013-02-19 133 views
7
#include <functional> 

void f1(int) 
{} 

void f2(int, ...) 
{} 

int main() 
{ 
    std::function<void(int)>  g1 = f1; // OK. 
    std::function<void(int, ...)> g2 = f2; // Error! Not standard C++! 
} 

为什么C++ 11没有提供专门的模板类,如下所示:为什么C++ 11不支持'std :: function <void(int,...)>'?

template<class ResultType, class... ArgTypes> 
class function<ResultType(ArgTypes......)> 
{ 
    // ... ... ... 
}; 
+0

你测试了一个看起来像这样的模板吗? – Omnifarious 2013-02-19 02:02:08

+1

你的两个片段显示完全不同的东西。变量模板在编译时处理。 “C”风格的变量参数在运行时处理。 – mfontanini 2013-02-19 02:12:56

+0

保留'...'(不包含可变参数模板)参数语法,以便与C向后兼容。其使用非常令人沮丧。 – 2013-02-19 02:26:05

回答

5

我并不想提供,为什么不提供专业化的最终原因(我不知道),但也许我可以暗示一些尝试实现它时可能遇到的技术障碍。这将有希望让你感觉为什么专业化不在那里。

让我们先考虑如何实现std::function<>类模板本身。该underlies其设计类型擦除技术可如下勾画(这仅仅是一个说明性简化,真正的实现方式更加复杂):

#include <memory> 

template<typename T> 
struct function { }; 

template<typename R, typename... Args> 
struct function<R(Args...)> 
{ 

public: 

    template<typename F> 
    function(F&& f) : _holder(
     new holder<typename std::decay<F>::type>(std::forward<F>(f)) 
     ) 
    { } 

    R operator() (Args&&... args) 
    { _holder->call(std::forward<Args>(args)...); } 

private: 

    struct holder_base 
    { virtual R call(Args&&... args) = 0; }; 

    template<typename F> 
    struct holder : holder_base 
    { 
     holder(F&& f) : _f(std::forward<F>(f)) { } 
     R call(Args&&... args) { return _f(std::forward<Args>(args)...); } 
     F _f; 
    }; 

    std::unique_ptr<holder_base> _holder; 
}; 

现在让我们来看看如何为椭圆专业化会是什么样子。首先,提供给可变参数函数的参数的数量和类型是而不是固定在该函数的签名中。因此,我们的专业模板的调用操作符必须是一个函数模板接受的参数中的任何数量和类型:

template<typename R, typename... Args> 
struct function<R(Args.......)> 
{ 
    ... 

    template<typename... Ts> 
    R operator() (Args&&... args, Ts&&... ts) 
    { _holder->call(std::forward<Args>(args)..., std::forward<Ts>(ts)...); } 

    ... 

这迫使我们反过来使holder<>的电话运营商一个可变参数函数模板。但是,为了实现类型擦除,相同的调用操作符必须为virtual,而C++中的功能模板不能为virtual

如果可变参数(我在这里讨论的是省略号)可以很容易地转发,而不必重复使用可变参数模板参数和完美的转发,情况肯定会更容易。我不知道有一个简单的方法来实现这个目标,特别是如果没有其他参数要传递给函数,那么与那些匹配可变参数列表的参数不同。

+0

我认为你还可以采取其他一些方法。但是,实施它的技术挑战让我的头部受到伤害,我不确定它可以完全干净地完成。 – Omnifarious 2013-02-19 03:39:21

+0

你可能会尝试传递一个'va_args'对象给虚拟的'operator()(Args ...,va_args vargs)',然后尝试以某种方式扩展'holder'的operator() ...但我认为这将是非常混乱。 – Xeo 2013-02-19 08:57:30

相关问题