Workaround for VS 2013 SFINAE deficiencies - c++

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.

Related

Visual Studio warning about function not in global namespace

I didn't really know what to write in the title, but basically I have a single .cpp, with only standard library headers included and no "using" keywords. I made my own "generate(...)" function. After including the library, Visual Studio shows me an error (where the function is being called), basically saying that it doesn't know whether to choose std::generate(...) or generate(...) because they have matching argument lists.
Is this a bug or have I missed something? I might also add that I am using VS2015.
#include <iostream>
#include <ctime>
#include <vector>
#include <algorithm>
template<typename Iter, typename Function>
Function generate(Iter begin, Iter end, Function f)
{
while (begin != end)
{
*begin = f();
++begin;
}
return f;
}
class Random
{
public:
Random(int low, int high)
: mLow(low), mHigh(high)
{}
int operator()()
{
return mLow + rand() % (mHigh - mLow + 1);
}
private:
int mLow;
int mHigh;
};
class Print
{
void operator()(int t)
{
std::cout << t << " ";
}
};
int main()
{
srand(time(0));
std::vector<int> intVec;
intVec.resize(15);
Random r(2, 7);
generate(intVec.begin(), intVec.end(), r);
}
Error output:
1>------ Build started: Project: Functor, Configuration: Debug Win32 ------
1> Main.cpp
1>c:\users\michael sund\documents\visual studio 2015\projects\gi_cpp\functor\main.cpp(44): warning C4244: 'argument': conversion from 'time_t' to 'unsigned int', possible loss of data
1>c:\users\michael sund\documents\visual studio 2015\projects\gi_cpp\functor\main.cpp(50): error C2668: 'generate': ambiguous call to overloaded function
1> c:\users\michael sund\documents\visual studio 2015\projects\gi_cpp\functor\main.cpp(7): note: could be 'Function generate<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>,Random>(Iter,Iter,Function)'
1> with
1> [
1> Function=Random,
1> Iter=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\algorithm(1532): note: or 'void std::generate<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>,Random>(_FwdIt,_FwdIt,_Fn0)' [found using argument-dependent lookup]
1> with
1> [
1> _FwdIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>,
1> _Fn0=Random
1> ]
1> c:\users\michael sund\documents\visual studio 2015\projects\gi_cpp\functor\main.cpp(50): note: while trying to match the argument list '(std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>, std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>, Random)'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
This happens on not just VC++ (VS 2015), but g++ 4.9+ as well. The issue here is the tricky Argument Dependent Lookup (Koenig Lookup).
It looks at the two iterators you're adding and it sees the "generate" function in std because the iterators also come from the std namespace (this is the point of Argument Dependent Lookup).
This problem actually bit me at one point: when I wrote my own tie implementation that did a few things extra to tie. I had to call mine tye because Koenig Lookup caused the considered overloads to be equal in their ranking and thus cause an error like this.
Either prefix generate with :: to start lookup from the global namespace (::generate( vec.begin(), vec.end(), ... );), or name it differently.

Visual studio using the wrong template function for chrono::duration division

I was converting over some code to use the c++11 chrono library rather than using the ctime library, at least in part to get a better understanding on the chrono library. Most of it has gone great, except for trying to do division by two chrono::durations. I've reduced the offending code down to a simple example and it took me a while to figure out why it was giving me the error it is.
#include <chrono>
using namespace std;
int main()
{
chrono::milliseconds tickLength(16);
chrono::milliseconds futureDuration(200);
auto numTicks = futureDuration / tickLength;
}
This should access the function
template<class _Rep1,
class _Period1,
class _Rep2,
class _Period2> inline
typename common_type<_Rep1, _Rep2>::type
operator/(
const duration<_Rep1, _Period1>& _Left,
const duration<_Rep2, _Period2>& _Right)
but instead appears to be trying to use
template<class _Rep1,
class _Period1,
class _Rep2> inline
typename enable_if<is_convertible<_Rep2,
typename common_type<_Rep1, _Rep2>::type>::value
&& !_Is_duration<_Rep2>::value,
duration<typename common_type<_Rep1, _Rep2>::type, _Period1> >::type
operator/(
const duration<_Rep1, _Period1>& _Left,
const _Rep2& _Right)
and thus is trying to determine a common type between milliseconds and long long. The compiler output is:
1>------ Build started: Project: Playground, Configuration: Debug Win32 ------
1> playground.cpp
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\type_traits(1446): error C2446: ':' : no conversion from 'std::chrono::milliseconds' to '__int64'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> c:\users\XXX\documents\visual studio 2013\projects\playground\playground\playground.cpp(9) : see reference to class template instantiation 'std::common_type<__int64,std::chrono::milliseconds>' being compiled
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Am I doing something wrong in my code?
Is this a visual studio issue?
Is this a c++11 standard issue?
Your example code compiles for me using clang/libc++. And your description of what should be happening sounds right to me. Further, if I print out numTicks, I get 12, which is 200/16 (integer division).
Sounds like a visual stdio bug to me. I see nothing wrong with your code.

boost::fusion::invoke compiler error with Visual Studio 2013

Trying to compile the following call to boost::fusion::invoke in boost-1.56 fails in Visual Studio 2013 but there is no error when compiling with Visual Studio 2012.
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/fusion/functional.hpp>
void Function( int & output )
{
output = 12;
}
int main( int, char ** )
{
boost::fusion::vector1< int > parameters;
boost::function< void( int & ) > function = &Function;
boost::fusion::invoke( function, parameters );
return 0;
}
The compiler output is:
boost\fusion\functional\invocation\invoke.hpp(205): error C2039: 'type' : is not a member of 'boost::result_of<Function (const int &)>'
with
[
Function=boost::function<void (int &)>
]
boost\fusion\functional\invocation\invoke.hpp(163) : see reference to class template instantiation 'boost::fusion::detail::invoke_impl<boost::function<void (int &)>,Sequence,1,false,true>' being compiled
with
[
Sequence=const boost::fusion::vector1<int>
]
main.cpp(16) : see reference to class template instantiation 'boost::fusion::result_of::invoke<boost::function<void (int &)>,const boost::fusion::vector1<int>>' being compiled
It's failing when trying to instantiate boost::result_of with a const Sequence. I've looked in boost\fusion\functional\invocation\invoke.hpp and there are two overloads of boost::fusion::invoke, one is const and the other is non-const.
I think that the Visual Studio 2013 compiler is attempting to instantiate the const version even though that is not the one that should be called. If I comment out the const version in invoke.hpp the example compiles fine.
Is this a bug with Visual Studio 2013 or boost-1.56?
Is there any workaround for this problem without modifying the boost sources?
I suspect the default for BOOST_RESULT_OF has changed for VS2013.
#define BOOST_RESULT_OF_USE_TR1
makes it compile. Chances are this bug is known and has been fixed in trunk, but you might want to report it still

What is this compiler error when using a lambda as a template parameter?

Edit:
This has been reported as a VS2012 C++ compiler bug on Microsoft Connect (link).
Nov. 11, 2014: Microsoft has responded saying the fix for this bug should show up in the next major release of Visual C++.
I've been struggling with a VS2012 compiler error message I don't understand, so I trimmed down the problem to what seems like the bare minimum.
I'm building the following main.cpp using VS2012:
#include <utility>
template <typename T>
struct A
{
T x;
A(A&& other) : x(std::move(other.x)) { }
A(T&& x) : x(std::move(x)) { }
};
template <typename T>
A<T> build(T&& x)
{
return A<T>(std::move(x));
}
int main(int argc, char* argv[])
{
auto f = []()
{
return build([](){}); //error here
};
return 0;
}
The salient point is that I'm trying to use a lambda as the template type T of the build function. The error message I get is:
1> main.cpp
1>C:\test\main.cpp(21): error C2664: 'A<T>::A(A<T> &&)' : cannot convert parameter 1 from 'A<T>' to 'A<T> &&'
1> with
1> [
1> T=void (__cdecl *)(void)
1> ]
1> and
1> [
1> T=main::<lambda_c3c618d445b3cb24eede9bf304860ad7>::()::<lambda_4240e93016e3e420ff8383c9350ae130>
1> ]
1> and
1> [
1> T=void (__cdecl *)(void)
1> ]
1> Reason: cannot convert from 'A<T>' to 'A<T>'
1> with
1> [
1> T=main::<lambda_c3c618d445b3cb24eede9bf304860ad7>::()::<lambda_4240e93016e3e420ff8383c9350ae130>
1> ]
1> and
1> [
1> T=void (__cdecl *)(void)
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
I've done my research and looked up the page for the error message (link), but I still can't figure out what the problem is. Could you please explain this compiler error?
edit
Something is definitely weird here. If I change the code in main to look like this:
auto f = []()
{
int* n = new int(0);
auto g = [=](){ return *n; };
*n++;
return build<decltype(g)>(std::move(g));
};
I get an error message suggesting that T=int (__cdecl *)(void) in the call to build - which would mean that decltype(g) is giving me a function pointer? Huh? I'm capturing a pointer by value and then modifying it afterwards - shouldn't it have to create a functor - and one that has no cast to function pointer? Maybe I'm not understanding something.
See related: Lambda expressions : n3290 draft
Also, if this is a bug in the VS2012 compiler, can you think of a workaround?
I can confirm that using GCC (on linux), this code compiles just fine.
So I'd say that VisualStudio seems to be the source of the error.
I don't have Windows or Visual Studio to verify, nor do I have much experience with lambda functions in C++, but perhaps you need to include the (albeit empty) parameter list in the function? i.e. change line 21 to
return build([](){});
Both versions compile with GCC, but perhaps Visual Studio is a bit more picky.
The other question I might have is whether the lambda function you're defining at line 24 will work out since its return value involves the lambda function you're defining inside the function itself.
I do not know if that behavior comply with the standard but with VC++ 2019 that error happen only with the option /permissive-, then when the strict mode is on.
Nevertheless here is how to solve the problem, by just casting the lambda with a reference type:
template <typename FUNC>
void f(FUNC& o){}
int main()
{
f((std::function<void()>&)[](){});
// or also:
auto func = [](){};
f(func);
}

C++ pointer-to-method template deduction doesn't compile when targeting x86, but works with x64

I've got this sample code:
struct A
{
int foo() { return 27; }
};
template<typename T>
struct Gobstopper
{
};
template<>
struct Gobstopper<int(void)>
{
Gobstopper(int, int) { } // To differentiate from general Gobstopper template
};
template<typename ClassType, typename Signature>
void DeduceMethodSignature(Signature ClassType::* method, ClassType& instance)
{
// If Signature is int(), Gobstopper<> should resolve to the specialized one.
// But it only does on x64!
Gobstopper<Signature>(1, 2);
}
int main(int argc, char** argv)
{
A a;
DeduceMethodSignature(&A::foo, a);
return 0;
}
This compiles fine with g++. It also compiles fine with VC10, but only when building for the 64-bit platform. When I build for the 32-bit platform, I get this compile error:
error C2661: 'Gobstopper<T>::Gobstopper' : no overloaded function takes 2 arguments
1> with
1> [
1> T=int (void)
1> ]
1> c:\...\test.cpp(26) : see reference to function template instantiation 'void DeduceMethodSignature<A,int(void)>(Signature (__thiscall A::* ),ClassType &)' being compiled
1> with
1> [
1> Signature=int (void),
1> ClassType=A
1> ]
The error indicates that the non-specialized version of Gobstopper is being used, which must mean the Signature is something other that int (void). But the error also clearly says that Signature is int (void). So where does the error come from? And how can I fix it?
The only thing I can think of that might change from 32-bit to 64-bit and not show up in the signature displayed in the error message is the calling convention; apparently, there is a unified calling convention for VC x64, whereas for x86 each calling convention is distinct. But even if that's the problem, I have no idea how to fix it.
Edit: I should mention that I tried this with regular (non-member) function pointers, and that worked fine.
You are quite correct.
The type of Signature with a Win32 target is int __thiscall(void) while on x64 it is int __cdecl(void). Note that on either target the type of non-member functions commonly called int(void) is indeed int __cdecl(void) so, by coincidence one of the constructed types actually (not really correctly!) matches.
In general it is not advisable to mix the different types of function pointers by template magic, so the Gobstopper specialization should look at something like int (ClassType::*)() instead.