I'm trying to fix up a library (entityx) that does not currently compile on Windows using VS 2013. It compiles fine on Linux with gcc and also on Windows with MinGW.
It seems the problem is with SFINAE - I guess VS 2013 doesn't properly ignore substitution failures for templates.
There is a report of this issue on Microsoft Connect, here.
Before I dive into entityx, there is a sample of the problem (taken from the report at Microsoft Connect):
#include <vector>
#include <future>
using namespace std;
typedef int async_io_op;
struct Foo
{
//! Invoke the specified callable when the supplied operation completes
template<class R> inline std::pair < std::vector < future < R >> , std::vector < async_io_op >> call(const std::vector<async_io_op> &ops, const std::vector < std::function < R() >> &callables);
//! Invoke the specified callable when the supplied operation completes
template<class R> std::pair < std::vector < future < R >> , std::vector < async_io_op >> call(const std::vector < std::function < R() >> &callables) { return call(std::vector<async_io_op>(), callables); }
//! Invoke the specified callable when the supplied operation completes
template<class R> inline std::pair<future<R>, async_io_op> call(const async_io_op &req, std::function<R()> callback);
//! Invoke the specified callable when the supplied operation completes
template<class C, class... Args> inline std::pair<future<typename std::result_of<C(Args...)>::type>, async_io_op> call(const async_io_op &req, C callback, Args... args);
};
int main(void)
{
Foo foo;
std::vector<async_io_op> ops;
std::vector < std::function < int() >> callables;
foo.call(ops, std::move(callables));
return 0;
}
I get the following error when attempting to compile this:
error C2064: term does not evaluate to a function taking 0 arguments
c:\program files (x86)\microsoft visual studio 12.0\vc\include\xrefwrap 58
Apparently, we can use std::enable_if
to work around this problem. However, I can't figure out how.
Does anyone know how I can fix this compile error?
Edit: Full output from VS 2013:
1>------ Build started: Project: VS2013_SFINAE_Failure, Configuration: Debug Win32 ------
1> test_case.cpp
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xrefwrap(58): error C2064: term does not evaluate to a function taking 0 arguments
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\xrefwrap(118) : see reference to class template instantiation 'std::_Result_of<_Fty,>' being compiled
1> with
1> [
1> _Fty=std::vector<std::function<int (void)>,std::allocator<std::function<int (void)>>>
1> ]
1> c:\users\jarrett\downloads\vs2013_sfinae_failure\vs2013_sfinae_failure\test_case.cpp(25) : see reference to class template instantiation 'std::result_of<std::vector<std::function<int (void)>,std::allocator<_Ty>> (void)>' being compiled
1> with
1> [
1> _Ty=std::function<int (void)>
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
VS2013 compiles the code if you replace std::result_of
with its decltype
+ std::declval
equivalent. So change the last Foo::call()
definition to
template<class C, class... Args>
inline pair<future<decltype(declval<C>()(declval<Args>()...))>, async_io_op>
call(const async_io_op& req, C callback, Args... args);
If I understand the error correctly, it's related to the defect described here, but then it's surprising that both GCC and clang manage to compile the result_of
code without errors.