问题
The following code does not compile in GCC 4.7.2 or Clang 3.2:
#include <vector>
#include <functional>
int main()
{
std::vector<std::function<void()>> a;
std::vector<std::function<void()>> b{a};
}
The issue is that the compiler will try to create b using an initializer_list, when clearly it should just be calling the copy constructor. However this seems to be desired behavior because the standard says that initializer_list constructors should take precedence.
This code would work fine for other std::vector, but for a std::function the compiler can't know whether you want the initializer_list constructor or another one.
It doesn't seem like there is a way around it, and if that is the case then you can never use uniform initialization in templated code. Which would be a giant shame.
Visual Studio (2012 November CTP) on the other hand doesn't complain about this. But the initializer_list support is not very good in there at the moment, so it might be a bug.
回答1:
This is LWG 2132 which is not yet a Defect Report but there's clear consensus (and implementation experience) to fix it. The standard says that std::function
's constructor will accept any type, so because an initializer-list constructor is always preferred to other constructors if it's viable, your code tries to construct a vector from an std::initializer_list<std::function<void()>>
with a single element initialized from the object a
. That then causes an error because although you can construct a std::function<void()>
from a
the resulting object isn't callable.
In other words the issue is that std::function
has an unconstrained template constructor allowing conversion from any type. That causes a problem in your case because initializer-list constructors are preferred to other constructors if viable, and the unconstrained function
constructor means it's always possible to create an initializer_list<function<void()>>
from any type so an initializer-list constructor is always viable.
The proposed resolution to 2132 prevents constructing a std::function
from a non-callable type, so the initializer-list constructor isn't viable and the vector
copy constructor is called instead. I implemented that resolution for GCC 4.8, and it's already implemented in Clang's libc++ library too.
回答2:
I can't see any reason why this shouldn't compile and both gcc (version 4.8.0 20121111) and clang (version 3.3 (trunk 171007)) compile the code. That said, "uniform initialization" is far from uniform: There are definitely cases where you can't use braces when invoking a constructor.
来源:https://stackoverflow.com/questions/14087600/cant-copy-a-stdvectorstdfunctionvoid-using-uniform-initialization-i