clang 3.4 accepts the following code; while vc++ NOV 2013 CTP rejects it with an error:
error C2668: 'AreEqual' : ambiguous call to overloaded function
template<class headT, class... tailTypes>
constexpr headT&& __GetFirst__(headT&& value, tailTypes&&...)
{
return static_cast<headT&&>(value);
};
template<class T>
constexpr bool AreEqual(const T& a, const T& b)
{
return a == b;
}
template<class headT, class... tailTypes>
constexpr bool AreEqual(const headT& head_value, const tailTypes&... tail_values)
{
return AreEqual(head_value, __GetFirst__(tail_values...))
&& AreEqual(tail_values...);
}
int main()
{
AreEqual(1, 1, 2, 1);
}
Which compiler is correct as per the C++14 standard?
Update: The full error message:
error C2668: 'AreEqual' : ambiguous call to overloaded function
1> d:\projects\ktl\test\main.cpp(20): could be 'bool AreEqual<headT,int>(const headT &,const int &)'
1> with
1> [
1> headT=int
1> ]
1> d:\projects\ktl\test\main.cpp(8): or 'bool AreEqual<headT>(const T &,const T &)'
1> with
1> [
1> headT=int
1> , T=int
1> ]
1> while trying to match the argument list '(const int, const int)'
1>
1>Build FAILED.
Clang (and GCC)'s behavior is correct. You can read ยง14.8.2.4 [temp.deduct.partial] of the standard for how the partial ordering for function templates is done, but the example given in p8 of that subclause directly covers this situation:
template<class... Args> void f(Args... args); // #1
template<class T1, class... Args> void f(T1 a1, Args... args); // #2
template<class T1, class T2> void f(T1 a1, T2 a2); // #3
f(); // calls #1
f(1, 2, 3); // calls #2
f(1, 2); // calls #3; non-variadic template #3 is more
// specialized than the variadic templates #1 and #2
Related
I have a C++ template function being used in VS2013 without any problem. But when I upgrade to VS2017 the VC compiler complains it cannot match the argument list. Anyone can help me how to fix the code?
A simplified code snippet that demonstrates the problem here:
#include "stdafx.h"
#include <functional>
#include <memory>
class FS
{
};
typedef std::shared_ptr<FS> FSPtr;
class FSM
{
public:
FSM() : m_pFs(new FS()) {}
template <typename CALLABLE, typename... ARGS>
typename std::enable_if<std::is_same<bool, std::result_of_t<CALLABLE(ARGS&&...)>>::value, std::result_of_t<CALLABLE(ARGS&&...)>>::type
All(CALLABLE fn, ARGS&&... args) const // line 21
{
std::function<bool()> rFunc = std::bind(fn, m_pFs, args...);
bool bSuccess = rFunc();
return bSuccess;
}
private:
FSPtr m_pFs;
};
class SFF
{
public:
SFF() : m_pFsm(new FSM()) {}
bool VF(FSPtr pFs)
{
return nullptr != pFs;
}
bool Do()
{
return m_pFsm->All(std::bind(&SFF::VF, this, std::placeholders::_1)); // line 41
}
bool TF(FSPtr pFs, int n)
{
return nullptr != pFs && 0 != n;
}
bool Do1(int n)
{
return m_pFsm->All(std::bind(&SFF::TF, this, std::placeholders::_1, std::placeholders::_2), n); // line 49
}
private:
std::shared_ptr<FSM> m_pFsm;
};
int _tmain(int argc, _TCHAR* argv[])
{
SFF oSff;
bool bOk1 = oSff.Do();
bool bOk2 = oSff.Do1(4);
int rc = (bOk1 && bOk2) ? 0 : 1;
return rc;
}
And the errors VS2017 VC compiler output is:
1>------ Build started: Project: ConsoleApplication1, Configuration: Debug Win32 ------
1>ConsoleApplication1.cpp
1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.11.25503\include\utility(486): error C2338: tuple index out of bounds
1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.11.25503\include\functional(887): note: see reference to class template instantiation 'std::tuple_element<0,std::tuple<>>' being compiled
1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.11.25503\include\tuple(793): note: see reference to function template instantiation 'const tuple_element<_Index,_Tuple>::type &&std::get(const std::tuple<_Rest...> &&) noexcept' being compiled
1> with
1> [
1> _Tuple=std::tuple<_Rest...>
1> ]
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(41): note: see reference to class template instantiation 'std::result_of<std::_Binder<std::_Unforced,bool (__thiscall SFF::* )(FSPtr),SFF *,const std::_Ph<1> &> (void)>' being compiled
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(21): note: while compiling class template member function 'std::enable_if<std::is_same<bool,result_of<_Ty>::type>::value,result_of<_Ty>::type>::type FSM::All(CALLABLE,ARGS &&...) const'
1> with
1> [
1> _Ty=CALLABLE (ARGS &&...)
1> ]
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(41): error C2672: 'FSM::All': no matching overloaded function found
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(41): error C2893: Failed to specialize function template 'std::enable_if<std::is_same<bool,result_of<_Ty>::type>::value,result_of<_Ty>::type>::type FSM::All(CALLABLE,ARGS &&...) const'
1> with
1> [
1> _Ty=CALLABLE (ARGS &&...)
1> ]
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(41): note: With the following template arguments:
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(41): note: 'CALLABLE=std::_Binder<std::_Unforced,bool (__thiscall SFF::* )(FSPtr),SFF *,const std::_Ph<1> &>'
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(41): note: 'ARGS={}'
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(49): error C2672: 'FSM::All': no matching overloaded function found
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(49): error C2893: Failed to specialize function template 'std::enable_if<std::is_same<bool,result_of<_Ty>::type>::value,result_of<_Ty>::type>::type FSM::All(CALLABLE,ARGS &&...) const'
1> with
1> [
1> _Ty=CALLABLE (ARGS &&...)
1> ]
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(49): note: With the following template arguments:
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(49): note: 'CALLABLE=std::_Binder<std::_Unforced,bool (__thiscall SFF::* )(FSPtr,int),SFF *,const std::_Ph<1> &,const std::_Ph<2> &>'
1>c:\users\s.chan\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(49): note: 'ARGS={int &}'
1>Done building project "ConsoleApplication1.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Any help is much appreciated.
Apparently fn (CALLABLE) in FSM::All() is supposed to be called as fn(m_pFs, args...), not fn(args...)
So your SFINAE is wrong:
std::result_of_t<CALLABLE(ARGS&&...)> is missing the m_pFs argument:
std::result_of_t<CALLABLE(FSPtr, ARGS&&...)>
If you add FSPtr it should work. But keep in mind that result_of is deprecated. You can achieve the same effect simply with a trailing return type:
template <typename CALLABLE, typename... ARGS>
auto All(CALLABLE fn, ARGS&&... args)
-> std::enable_if_t<std::is_same_v<bool, decltype(fn(std::declval<FSPtr>(), args...))>, bool>
{
Note also that std::bind returns a lambda. Creating an std::function from that will be inefficient. Better to just use the returned type as-is:
auto rFunc = std::bind(fn, m_pFs, args...); // no need to cast to std::function
rFunc();
The reason why your code doesn't compile is the following:
bool Do()
{
return m_pFsm->All(std::bind(&SFF::VF, this, std::placeholders::_1));
}
Here you use wrapper function All to call VF function. But:
1) All function is supposed to get the function arguments:
template <typename CALLABLE, typename... ARGS>
typename std::enable_if<std::is_same<bool, std::result_of_t<CALLABLE(ARGS&&...)>>::value, std::result_of_t<CALLABLE(ARGS&&...)>>::type
All(CALLABLE fn, ARGS&&... args) const // line 21
{
std::function<bool()> rFunc = std::bind(fn, m_pFs, args...);
bool bSuccess = rFunc();
return bSuccess;
}
Args here should stand for single argument of FSPtr type, see the signature of SFF::VF.
So the correct code should be:
return m_pFsm->All(std::bind(&SFF::VF, this, std::placeholders::_1), somethingOfFSPtrType);
I'm trying to use a variant's visitor for multiple types and then generating a new random value. Be aware that I can't use more recent compiler than Visual Studio 2015 Update 3 and GCC 4.9 because of reasons out of my control.
Here is what I have
std::random_device randomDevice;
std::mt19937 randomEngine(randomDevice());
typedef mpark::variant< // Implementation of std::variant for C++11,14
bool,
int8_t, uint8_t,
int16_t, uint16_t,
int32_t, uint32_t,
int64_t, uint64_t,
float, double,
std::string
> VariantValue;
struct ValueVisitor
{
ValueVisitor(VariantValue* pNewVal)
: pNewVal(pNewVal) {}
void operator()(const std::string & s) const
{
// Generate some random string into *pNewVal
}
void operator()(const bool& t) const
{
*pNewVal = !t;
}
template <typename T,
std::enable_if_t<std::is_integral<T>::value>* = nullptr,
std::enable_if_t<!std::is_same<T, bool>::value>* = nullptr>
>
void operator()(const T& t) const
{
std::uniform_int_distribution<T> dist
(
std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()
);
*pNewVal = dist(randomEngine);
}
template <typename T, typename std::enable_if<
std::is_floating_point<T>::value>::type* = nullptr>
void operator()(const T& t) const
{
std::uniform_real_distribution<T> dist
(
std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()
);
*pNewVal = dist(randomEngine);
}
VariantValue* pNewVal;
};
VariantValue vSource {(double)12 };
VariantValue vTarget;
ValueVisitor valueVisitor(&vTarget);
mpark::visite(valueVisitor, v);
But I'm getting the error C2338 invalid template argument for uniform_int_distribution.
Looking at output window for more details
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\random(2387): error C2338: invalid template argument for uniform_int_distribution
1> d:\project\xxx.cpp(271): note: see reference to class template instantiation 'std::uniform_int_distribution<T>' being compiled
1> with
1> [
1> T=int8_t
1> ]
1> d:\project\3rdparty\mpark\include\mpark\lib.hpp(237): note: see reference to function template instantiation 'void ValueVisitor::operator ()<T,void>(const T &) const' being compiled
1> with
1> [
1> T=int8_t
1> ]
...
So, If I well understood, it seems that when T=bool the functor's function targeted is the one for is_integral. But why ? I explicitly removed the bool type with std::enable_if_t<!std::is_same<T, bool>::value>* = nullptr.
I tried a different approaches like
template <typename T>
void operator()(const T & t)
{
if (std::is_same<T, bool>::value) {
} else if (std::is_floating_point<T>::value) {
} else if (std::is_integral<T>::value) {
} else if (std::is_same<T, std::string>::value) {
}
But without success, it's worst as now the float variation are still trying to use the uniform_int_distribution.
I'm really out of idea.
Best regards,
I learned a bit about variadic templates and searched over the Internet for some samples and now trying to write some tricky code to call member a method of a variadic class template with one of its fields. I can't understand why it doesn't work. Please, help.
Here is sample classes:
class BarBase
{
public:
BarBase() = default;
virtual void call() = 0;
};
template<typename O, typename M, typename... A>
class Bar
: public BarBase
{
public:
Bar(O* o, M m, A&&... a)
: BarBase()
, m_o(o), m_m(m), m_a(std::forward<A>(a)...)
{ }
void call() override final
{
callInnerWithArgsInside();
}
private:
void callInnerWithArgsInside()
{
(m_o->*m_m)(m_a); // Some errors happends here
}
O* m_o;
M m_m;
std::tuple<typename std::remove_reference<A>::type...> m_a;
};
template<typename O, typename M, typename... A>
BarBase* crateBar(O* o, M m, A&&... a)
{
return new Bar<O, M, A...>(o, m, std::forward<A>(a)...);
}
And call from main:
struct Foo
{
void foo(int ii, float ff, std::string ss)
{
std::cout << "called" << std::endl;
}
};
int main()
{
Foo f;
int i = 10;
float ff = 20.2f;
std::string s = "Hello";
BarBase* bar = crateBar(&f, &Foo::foo, i, ff, s);
bar->call();
}
Errors:
main.cpp
1>d:\drafts_tests\main.cpp(203): error C2198: 'void (__thiscall Foo::* )(int,float,std::string)' : too few arguments for call
1> d:\drafts_tests\main.cpp(202) : while compiling class template member function 'void Bar::callInnerWithArgsInside(void)'
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(197) : see reference to function template instantiation 'void Bar::callInnerWithArgsInside(void)' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(214) : see reference to class template instantiation 'Bar' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(225) : see reference to function template instantiation 'BarBase *crateBar(O *,M,int &,float &,std::string &)' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
you are passing a tuple to the function, rather than the individual type arguments. The following will pass the required type args to the call:
template<std::size_t... I>
void callInnerWithArgsInside2(std::index_sequence<I...>)
{
(m_o->*m_m)(std::get<I>(m_a)...);
}
void callInnerWithArgsInside()
{
return callInnerWithArgsInside2( std::make_index_sequence<sizeof...(A)>());
}
live demo
EDIT1: C++11 version
I have implemented a C++11 version, see updated live demo
I want to make a template function to queue both general functions and also class member functions. With internet search, I came up with the following code but have error in compiling it.
#include <iostream>
#include <functional>
#include <queue>
#include <string>
double MyFunction(double num1, double num2)
{
std::cout << "MyFunction( " << num1 << ", " << num2 << " )\n";
return num1 + num2;
}
class MyClass
{
public:
double MyClassFunction(double num1, double num2, double num3) const
{
std::cout << "MyClass::MyClassFunction( " << num1 << ", " << num2 << ", " << num3 << " )\n";
return num1 + num2 + num3;
}
};
struct MyFunctionQueue
{
template <typename FUNC, typename... ARGS>
void QueueFunction(FUNC fn, ARGS&&... args)
{
std::function<std::result_of_t<FUNC(ARGS...)> () > rFunc = std::bind(fn, args...);
_myFQ.push(rFunc);
}
void Execute()
{
while (!_myFQ.empty())
{
_myR.push(_myFQ.front()());
_myFQ.pop();
}
}
double PopResult()
{
double r = _myR.front();
_myR.pop();
return r;
}
std::queue<std::function<double()>> _myFQ;
std::queue<double> _myR;
};
int main()
{
MyFunctionQueue funcQue;
funcQue.QueueFunction(MyFunction, 1.234, 2.345);
MyClass obj;
funcQue.QueueFunction(&MyClass::MyClassFunction, std::ref(obj), 1.234, 2.345, 3.456);
funcQue.Execute();
std::cout << "MyFunction result: " << funcQue.PopResult() << std::endl;
std::cout << "MyClass::MyClassFunction result: " << funcQue.PopResult() << std::endl;
}
I know the error is with the template code generation on the class member function. With my limited knowledge in using templates I cannot figure out what's wrong with it. Can anyone help to point out the mistake in the code? And the error I've got from VC++ is:
1>------ Build started: Project: TestFunctionQueue, Configuration: Debug Win32 ------
1> TestFunctionQueue.cpp
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1469): error C2672: 'std::invoke': no matching overloaded function found
1> c:\users\siu.chan\documents\visual studio 2015\projects\testfunctionqueue\testfunctionqueue\testfunctionqueue.cpp(31): note: see reference to class template instantiation 'std::result_of<FUNC (std::reference_wrapper<MyClass>,double,double,double)>' being compiled
1> with
1> [
1> FUNC=double (__thiscall MyClass::* )(double,double,double) const
1> ]
1> c:\users\siu.chan\documents\visual studio 2015\projects\testfunctionqueue\testfunctionqueue\testfunctionqueue.cpp(63): note: see reference to function template instantiation 'void MyFunctionQueue::QueueFunction<double(__thiscall MyClass::* )(double,double,double) const,std::reference_wrapper<MyClass>,double,double,double>(FUNC,std::reference_wrapper<MyClass> &&,double &&,double &&,double &&)' being compiled
1> with
1> [
1> FUNC=double (__thiscall MyClass::* )(double,double,double) const
1> ]
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1469): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1469): note: With the following template arguments:
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1469): note: '_Callable=double (__thiscall MyClass::* )(double,double,double) const'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1469): note: '_Types={std::reference_wrapper<MyClass>, double, double, double}'
1>c:\users\siu.chan\documents\visual studio 2015\projects\testfunctionqueue\testfunctionqueue\testfunctionqueue.cpp(31): error C2440: 'initializing': cannot convert from 'std::_Binder<std::_Unforced,FUNC &,std::reference_wrapper<MyClass> &,double &,double &,double &>' to 'std::function<unknown-type (void)>'
1> with
1> [
1> FUNC=double (__thiscall MyClass::* )(double,double,double) const
1> ]
1> c:\users\siu.chan\documents\visual studio 2015\projects\testfunctionqueue\testfunctionqueue\testfunctionqueue.cpp(31): note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>c:\users\siu.chan\documents\visual studio 2015\projects\testfunctionqueue\testfunctionqueue\testfunctionqueue.cpp(32): error C2664: 'void std::queue<std::function<double (void)>,std::deque<_Ty,std::allocator<_Ty>>>::push(const std::function<double (void)> &)': cannot convert argument 1 from 'std::function<unknown-type (void)>' to 'std::function<double (void)> &&'
1> with
1> [
1> _Ty=std::function<double (void)>
1> ]
1> c:\users\siu.chan\documents\visual studio 2015\projects\testfunctionqueue\testfunctionqueue\testfunctionqueue.cpp(32): note: Reason: cannot convert from 'std::function<unknown-type (void)>' to 'std::function<double (void)>'
1> c:\users\siu.chan\documents\visual studio 2015\projects\testfunctionqueue\testfunctionqueue\testfunctionqueue.cpp(32): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
So, I think this is an issue with vc++. Passing a member function works just fine when the next parameter is a pointer, but fails when it is a reference.
template <class F, class... A>
std::result_of_t<F(A...)> Foo::bar(F f, A... a)
{
return 0;
}
Foo f;
f.bar(&Foo::other_function, std::ref(f)); //error
f.bar(&Foo::other_function, &f); //success
Additionally, result_of in vc++ fails when the function type is a function (like void()), but clang and gcc both succeed.
template <class F, class... A>
struct Foo
{
typedef std::result_of_t<F(A...)> type;
};
Foo<int(int), int> //fails in only vc++
Now I'm migrating my project from Visual Studio 2008 to 2013 (with no updates installed), and facing a problem.
I have a sort of Variant type, CData< T>, that has a conversion operators to the contained type T.
template<class T> T& GetValue();
template<class T> const T& GetValue() const;
template<class T> T* GetValuePtr();
template<class T> const T* GetValuePtr() const;
template<class T> operator T&() { return GetValue<T>(); }
template<class T> operator const T&() const { return GetValue<T>(); }
template<class T> operator T*() { return GetValuePtr<T>(); }
template<class T> operator const T*() const { return GetValuePtr<T>(); }
There are methods in a class CDataArray:
CData& Get(int Index) { return At(Index); }
const CData& Get(int Index) const { return operator [](Index); }
template<class T>
T& Get(int Index) { return At(Index).GetValue<T>(); }
template<class T>
const T& Get(int Index) const { return operator [](Index).GetValue<T>(); }
and there is a call to it:
Data::PDataArray SGQuests;
Data::PParams SGQuest = SGQuests->Get(i);
Here, Data::PParams is going to be T.
In VS2008, it seems it used non-const non-template CDataArray::Get(), which returned CData&, and then this CData& was accessed with non-const template operator T&(), finally returning Data::PParams&.
In VS2013, it for some reason uses a const overload and it results in error:
1>PATH_TO_SRC\l1\data\type.h(126): error C2678: binary "=": no operator found that accepts left operand "const Ptr<Data::CParams>" (or there is no acceptable conversion)
1> PATH_TO_SRC\l1\data\ptr.h(29): may be "void Ptr<Data::CParams>::operator =(T *)"
1> with
1> [
1> T=Data::CParams
1> ]
1> PATH_TO_SRC\l1\data\ptr.h(28): or "void Ptr<Data::CParams>::operator =(const Ptr<Data::CParams> &)"
1> trying to match argument list "(const Ptr<Data::CParams>, const Ptr<Data::CParams>)"
1> PATH_TO_SRC\l1\data\type.h(125): compiling member function "void Data::CTypeImpl<T>::Copy(void **,void *const *) const" template class
1> with
1> [
1> T=const Ptr<Data::CParams>
1> ]
1> PATH_TO_SRC\l1\data\data.h(167): "Data::CTypeImpl<T>"
1> with
1> [
1> T=const Ptr<Data::CParams>
1> ]
1> PATH_TO_SRC\l1\data\data.h(97): "T &Data::CData::GetValue<T>(void)"
1> with
1> [
1> T=const Ptr<Data::CParams>
1> ]
1> PATH_TO_SRC\l3\quests\questmanager.cpp(307): "Data::CData::operator const T(void)<const Ptr<Data::CParams>>"
1> with
1> [
1> T=const Ptr<Data::CParams>
1> ]
I translated messages to English manually, so they can slightly differ from original EN compiler messages.
And finally, if I write explicit template argument:
Data::PParams SGQuest = SGQuests->Get<Data::PParams>(i);
It compiles OK.
The questions are:
How VS2013 template argument guessing differs from VS2008 one? Is there any place (standard, article or smth) that clearly explains, why my old code shouldn't compile? Any reference would be appreciated.
How should I write code in that situations? Do I have to write template arguments explicitly now, or just modify member overloads, or install some update?
P.S. Minimal code is available at https://www.dropbox.com/s/zjohnu5v87tyr2c/ConstOverload.zip?dl=0 . Full source code is at
https://code.google.com/p/deusexmachina/source/browse/branches/Dev/DEM/Src
This problem was solved by adding third overload to CData
template<class T> operator const T&() { return GetValue<T>(); }
Original solution is posted in:
Conversion operator error C2678 in VS2013, works in VS2008
Look there for possible further details.