Pregunta

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 ==========
¿Fue útil?

Solución

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top