I have compiled the below code :
typedef unsigned char uint8;
template <uint8 N> inline uint8 g(uint8 x) { return x > N ? 1 : 0; }
template <size_t stride, size_t boxsize, class T, class F>
inline void boxfilt(size_t width, size_t size, T * inout, const F & f) {
}
template <class T> inline T self(const T & x) { return x; }
template <size_t stride, size_t boxsize, class T>
inline void boxfilt(size_t width, size_t size, T * inout) {
return boxfilt<stride, boxsize>(width, size, inout, self<T>);
}
int main(int argc, char* argv[])
{
uint8 *out = NULL;
boxfilt<3,4>(10,29,out,g<4>);
return 0;
}
In g++ compiler, it works fine. When I try to compile the same code in Visual Studio 2008 compiler, it shows the following error:
Error 1 error C2780: 'void boxfilt(size_t,size_t,T *)' : expects 3 arguments - 4 provided g:\testfjx\test\test.cpp
Error 2 error C2784: 'void boxfilt(size_t,size_t,T *,const F &)' : could not deduce template argument for 'overloaded function type' from 'overloaded function type' g:\testfjx\test\test.cpp
Error 3 error C2784: 'void boxfilt(size_t,size_t,T *,const F &)' : could not deduce template argument for 'T *' from 'uint8 *' g:\testfjx\test\test.cpp
How can I resolve this problem?
It is OK, in Visual C++ 2008 too.
If both VC++2008 and G++4.7.2 accept the code and VC++2005 doesn't, so maybe VC++2005 has bug, maybe it doesn't implement C++ specification completely.
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);
Given the following class and function templates:
template <typename WrappedType, ParameterType ParamType, bool IsOutputParameter>
class WrappedParameter; // Definition left out for brevity
template <typename T>
struct ParameterUnwrapper
{
static T UnwrapParameter(const T& in_param)
{
return in_param;
}
};
template <typename T, ParameterType ParamType, bool IsOutputParameter>
struct ParameterUnwrapper<WrappedParameter<T, ParamType, IsOutputParameter>>
{
static T UnwrapParameter(const WrappedParameter<T, ParamType, IsOutputParameter>& in_param)
{
return in_param.GetWrapped();
}
};
template <typename T>
T UnwrapParameter(T in_param)
{
return Impl::ParameterUnwrapper<T>::UnwrapParameter(in_param);
}
template <typename T>
Impl::WrappedParameter<T, Impl::POINTER_PARAMETER, true> WrapOutputPointerParameter(T in_param)
{
return Impl::WrappedParameter<T, Impl::POINTER_PARAMETER, true>(in_param);
}
template <typename MemFunc, typename ...Args>
HRESULT ExecuteAndLog(
MemFunc in_memberFunction,
const std::string& in_methodName,
Args... args) //-> decltype((m_wrapped->*in_memberFunction)(UnwrapParameter(args)...))
{
return ExecuteFunctorAndLog(
[&]() { return (m_wrapped->*in_memberFunction)(UnwrapParameter(args)...); },
in_methodName,
args...);
}
The following call: (The ExecuteAndLog)
HRESULT STDMETHODCALLTYPE AccessorWrapper::AddRefAccessor(
HACCESSOR hAccessor,
DBREFCOUNT *pcRefCount)
{
return ExecuteAndLog(
&IAccessor::AddRefAccessor,
"AddRefAccessor",
hAccessor,
WrapOutputPointerParameter(pcRefCount));
}
Gives me errors:
error C2664: 'HRESULT (HACCESSOR,DBREFCOUNT *)' : cannot convert argument 2 from 'Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>' to 'DBREFCOUNT *'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
see reference to function template instantiation 'ExecuteAndLog<HRESULT(__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *),HACCESSOR, Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>>(MemFunc,const std::string &,HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>)' being compiled
with
[
MemFunc=HRESULT (__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *)
]
see reference to function template instantiation 'ExecuteAndLog<HRESULT(__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *),HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>>(MemFunc,const std::string &,HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>)' being compiled
with
[
MemFunc=HRESULT (__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *)
]
I think I've messed up the partial specialization of ParameterUnwrapper (or my approach is just wrong). Any advice?
More information:
Impl is a nested namespace (alongside the namespace all the provided templates except ExecuteAndLog are in)
m_wrapped is of type IAccessor* (the COM interface) in this case.
enum ParameterType
{
POINTER_PARAMETER,
ARRAY_PARAMETER
};
UPDATE:
Here's a self contained example: http://codepad.org/lwTzVImb
The error I get in VS2013 for this one is:
error C2664: 'int (int,int **,size_t *)' : cannot convert argument 2 from 'WrappedParameter<int **,ARRAY_PARAMETER,true>' to 'int **'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
see reference to function template instantiation 'int ExecuteAndLog<int(__thiscall A::* )(int,int **,size_t *),int,WrappedParameter<int **,ARRAY_PARAMETER,true>,size_t*>(MemFunc,const std::string &,int,WrappedParameter<int **,ARRAY_PARAMETER,true>,size_t *)' being compiled
with
[
MemFunc=int (__thiscall A::* )(int,int **,size_t *)
]
I figured it out!
The issue was the return type of UnwrapParameter. Once I changed the declaration of it to
template <typename T>
auto UnwrapParameter(T in_param) -> decltype(Impl::ParameterUnwrapper<T>::UnwrapParameter(in_param))
It compiled. Shame the compiler didn't complain about the definition of that function, rather than trusting its declared return value.
I have some other problems right now but at least I've made progress.
My code is :
std::vector<double> Vec;
template<typename T>
void GetObj(VARIANT &vtProp)
{
CComSafeArray<T> SafeArray;
SafeArray.Attach(vtProp.parray);
ULONG Count = SafeArray.GetCount();
Vec.resize(Count);
for(ULONG Index = 0; Index < Count; Index++)
{
Vec[Index] = SafeArray[Index];
}
}
while compilation I got the error below:
error C2783: 'void __cdecl GetObj(struct tagVARIANT &)' : could not deduce template argument for 'T'
Kindly suggest me the correct answer
There is nothing in the function template's signature that allows the compiler to deduce the template type, so you need to be explicit:
GetObj<TheActualType>(arg);
I have a bunch of templated code that compiles fine under g++, but now when I try to build under windows with Visual C++ 2010 I get a bunch of errors.
I have a collection of template functions for getting and setting values in C++ objects from Lua code. For example, I have this template:
// Class Return type Getter function
template <typename T, typename U, U (T::*Getter)() const>
int luaU_get(lua_State* L)
{
T* obj = luaW_check<T>(L, 1); // Gets userdata from stack and checks if it's of type T
luaU_push(L, (obj->*Getter)()); // Runs the getter function specified in the template, and pushes the
return 1;
}
(The complete file can be found here)
Which is instantiated here:
static luaL_reg TextArea_MT[] =
{
// Class Return type Getter function
{ "GetCharacterSize", luaU_get<TextArea, unsigned int, &TextArea::GetCharacterSize> },
{ NULL, NULL }
};
The signature for that getter is as follows:
unsigned int GetCharacterSize() const;
I'm getting a bunch of errors like this:
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int *(__thiscall ag::ui::TextArea::* const )(void) const'
2> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(147) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int *ag::ui::TextArea::* const '
2> There is no context in which this conversion is possible
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(131) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int ag::ui::TextArea::* const '
2> There is no context in which this conversion is possible
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(123) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'lua_CFunction'
2> None of the functions with this name in scope match the target type
This is a compiler bug in VC++. The following code is valid:
#include <iostream>
struct TextArea
{
unsigned GetCharacterSize() const { return 0; }
};
template<typename T, typename U, U (T::*)() const>
int foo()
{
return 1;
}
template<typename T, typename U, U* (T::*)() const>
int foo()
{
return 2;
}
int main()
{
std::cout << foo<TextArea, unsigned, &TextArea::GetCharacterSize>() << '\n';
}
And compiles with GCC 4.3.4, GCC 4.5.1, and Comeau 4.3.10.1 Beta2 (no link), but yields the following error with VC++ 2010 SP1:
error C2668: 'foo' : ambiguous call to overloaded function
EDIT: As for a workaround, it's ugly, but the only thing I can think of offhand is to use an extra layer of indirection so that there is no overloading involved:
#include <iostream>
struct WithPointer
{
unsigned* GetCharacterSize() const { return nullptr; }
};
struct WithoutPointer
{
unsigned GetCharacterSize() const { return 0u; }
};
template<bool UsePointerImplB>
struct kludge
{
template<typename T, typename U, U (T::*Getter)() const>
static int foo() { return 1; }
};
template<>
struct kludge<true>
{
template<typename T, typename U, U* (T::*Getter)() const>
static int foo() { return 2; }
};
int main()
{
std::cout
<< kludge<false>::foo<WithoutPointer, unsigned, &WithoutPointer::GetCharacterSize>() << '\n'
<< kludge<true>::foo<WithPointer, unsigned, &WithPointer::GetCharacterSize>() << '\n';
}
Effectively this is no different than just giving each overload a different name...
If you can force user to pick the actual return type of the function, the following works. Maybe, it'll be useful to you:
#include <iostream>
struct FooBar
{
int Foo( void ) const
{
std::cout << "FooBar::Foo()" << std::endl;
return ( 0 );
}
int * Bar( void ) const
{
std::cout << "FooBar::Bar()" << std::endl;
return ( 0 );
}
};
template< typename P00, typename P01, P01(P00::*p02)( void ) const >
void Call()
{
P00 lT;
( lT.*p02 )();
}
int main( void )
{
Call< FooBar, int, &FooBar::Foo > ();
Call< FooBar, int*, &FooBar::Bar > ();
return( 0 );
}
Program output:
FooBar::Foo()
FooBar::Bar()
I'm trying to expose the following c++ function to python using boost.python:
template <typename genType>
genType refract(
genType const & I,
genType const & N,
typename genType::value_type const & eta);
and what I got is this:
template<typename N>
N reflect(N const & i, N const & n, typename N::value_type const & eta)
{
return glm::N refract(i,n,eta);
}
BOOST_PYTHON_MODULE(foo)
{
def("reflect", reflect<float>);
def("reflect", reflect<double>);
}
and I have the following error when compiling:
error C2780: 'void boost::python::def(const char *,F,const A1 &,const A2 &,const A3 &)' : expects 5 arguments - 2 provided
How should I wrap it?
-----edit------
This works:
template<class T>
T floor(T x)
{
return glm::core::function::common::floor(x);
}
BOOST_PYTHON_MODULE(busta)
{
def("floor", floor<double>);
def("floor", floor<float>);
}
from the reference, floor() definition is the folowing:
template< typename genType >
genType floor (genType const &x)
I can build this as a DLL, then import it in python and use floor() from there. Life feels so nice...but..
This won't work, and I would like to understand why:
template<class genType >
genType reflect (genType i, genType n, genType eta)
{
return glm::core::function::geometric::refract(i, n,eta);
}
BOOST_PYTHON_MODULE(busta)
{
def("reflect", reflect<float>);
}
refract() definition is on the top of this post.
the error I get now is this:
1>foo.cpp(37): error C2893: Failed to specialize function template 'genType glm::core::function::geometric::refract(const genType &,const genType &,const genType::value_type &)'
1> With the following template arguments:
1> 'float'
1> foo.cpp(60) : see reference to function template instantiation 'genType
`anonymous-namespace'::reflect<float>(genType,genType,genType)' being compiled
1> with
1> [
1> genType=float
1> ]
1>
1>Build FAILED.
This is not the perfect answer since it requires abusing the type system and writing plenty of additional glue code.
You could try defining a wrapper template to decorate your target type such that it would have the necessary typedefs to satisfy the calling function (reflect).
This example demonstrates the failings of such an approach. Notice that this reflect function performs a simple addition; however, for C++ to recognize the operator+ for the templated type N, the wrapper must explicitly define it.
#include <iostream>
using namespace std;
template<class N>
N reflect(const N& n, const typename N::value_type& t)
{
return n + t;
}
template<class N>
struct wrapper
{
typedef N value_type;
wrapper(const N& n):_n(n){}
operator N& () { return _n; }
N operator+ (const N& r) const { return _n + r; }
N _n;
};
int main(int,char**)
{
cout << reflect( wrapper<double>(1), 2.0) << endl;
return 0;
}