Why doesn't C ++ 11 support 'std :: function <void (int, ...)>'?

#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++! } 

Why C ++ 11 does not provide a specialized template class as follows:

 template<class ResultType, class... ArgTypes> class function<ResultType(ArgTypes......)> { // ... ... ... }; 
+7
source share
1 answer

I do not want to indicate why this specialization is not provided (I do not know this), but perhaps I could hint at some technical obstacles that may arise when trying to implement it. This, I hope, will give you a sense of why specialization is not there.

Let us first examine how the std::function<> template template itself can be implemented. The method of erasing the type that underlies its design can be described as follows (this is just an illustrative simplification, the real implementation is more complicated):

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

Now let's see what the specialization for ellipses will look like. First of all, the number and type of arguments provided to the variational function are not fixed in this function signature. Therefore, the call operator of our specialized template should be a function template that accepts any number and type of arguments:

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

This forces us, in turn, to make the call operator holder<> template of the variational function. However, in order to implement style erasure, the same call statement must be virtual , and function templates cannot be virtual in C ++.

Things, of course, would be simpler if the variational arguments (I'm talking about ellipses here) could be easily redirected without having to repeat the parameters of the variational pattern and perfect forwarding. I don’t know a simple way to achieve this, and especially if no other argument to the function is passed than those that correspond to the variational list.

+5
source

All Articles