I've inherited a project that has to be updated from MSVC platform toolset v100 to v140. Its for the upcoming release of Archicad. All is good except when I set the platform toolset to 140, one of my template function goes wild and got a compilation error:
C2064 term does not evaluate to a function taking 2 arguments
And I got a warning just after this for the same line:
class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments
The return statement in this block that is pointed by the IDE:
template<typename T, typename From>
inline T Convert(From from, const std::locale& locale)
{
converters::Converter<From, T> conv;
return conv(from, locale); // <- compilation fails on this line.
}
And I have several specializations like this:
CONVERTER(API_Guid, GS::Guid, from, locale)
{
(void)locale; // It gets optimized away
return APIGuid2GSGuid(from);
}
CONVERTER
is defined as:
#define CONVERTER(From, T, from, locale) \
template<> \
struct Converter<From, T> : public std::true_type \
{ \
inline T operator()(const From& from, const std::locale& locale) const; \
} ;\
T Converter<From, T>::operator()(const From& from, const std::locale& locale) const
An operator()
overload for the converter class. I've tried some workarounds like directly defining the Convert functions, but that way I've got linker errors.
Can somebody point out what am I missing? I had no problem compiling it with the older platform toolset. Did Microsoft changed something in the new one?
I've sandboxed the converter header, and narrowed it down. Marked the line which uncommented fails to compile, and throws the compilation error mentioned before (C2064).
Here is the reduced Convert.hpp:
#pragma once
#include <string>
#include "Declarations.hpp"
#include "utfcpp\utf8.h"
#define CONVERTER(From, T, from, locale) \
template<> \
struct Converter<From, T> : public std::true_type \
{ \
inline T operator()(const From& from, const std::locale& locale) const; \
} ;\
T Converter<From, T>::operator()(const From& from, const std::locale& locale) const
namespace et
{
template<typename T>
inline T Convert(const wchar_t* str, const std::locale& locale = std::locale::classic())
{
std::wstring wstr(str);
return Convert<T>(wstr, locale);
}
template<typename T, typename From>
inline T Convert(From from, const std::locale& locale)
{
converters::Converter<From, T> conv;
return conv(from, locale);
}
template<typename From>
inline std::string S(const From& from)
{
return Convert<std::string>(from);
}
inline std::string S(const wchar_t* from)
{
// return Convert<std::string>(from); <- This line fails to compile on V140, but does on V100
}
namespace converters
{
template<typename From, typename T, typename _Enabler1, typename _Enabler2, typename _Enabler3>
struct Converter : _FALSETYPE_
{
};
template<typename From, typename T>
struct Converter < From, T, _IF_CONVERTIBLE_(From, T) > : _TRUETYPE_
{
inline T operator()(const From& from, const std::locale&) const
{
return (T)from;
}
};
CONVERTER(std::string, bool, from, locale)
{
(void)locale; // It gets optimized away
return et::Convert<bool>(from.c_str());
}
CONVERTER(bool, std::string, from, locale)
{
(void)locale; // It gets optimized away
return from ? std::string("true") : std::string("false");
}
CONVERTER(std::string, et::UString, s, locale)
{
(void)locale; // It gets optimized away
et::UString dest;
utf8::utf8to16(s.begin(), s.end(), std::back_inserter(dest));
return dest;
}
CONVERTER(et::UString, std::string, from, locale)
{
(void)locale; // It gets optimized away
std::string dest;
utf8::utf16to8(from.begin(), from.end(), std::back_inserter(dest));
return dest;
}
}
}
And here is the Declarations.hpp for easier reproduction if anyone interested:
#pragma once
#include <string>
#define _TRUETYPE_ public std::true_type
#define _FALSETYPE_ public std::false_type
#define _IF_CONVERTIBLE_(From, To) typename std::enable_if<std::is_convertible<From, To>::value>::type
#define _IF_ARITHMETIC_(A) typename std::enable_if<std::is_arithmetic<A>::value>::type
#define _IF_ARITHMETIC_T_(A, T) typename std::enable_if<std::is_arithmetic<A>::value, T>::type
namespace et
{
template<typename T, typename Enabler = void, typename Blah = void>
struct IsConvertibleToString : public std::false_type
{
};
template<typename T>
struct IsConvertibleToString<T, typename std::enable_if<std::is_convertible<T, std::string>::value>::type > : public std::true_type
{
};
typedef std::u16string UString;
template<typename T, typename From>
T Convert(From from, const std::locale& locale = std::locale::classic());
template<typename From, typename T>
struct ConvertFunctor;
namespace converters
{
template<typename From, typename To, typename _Enabler1 = void, typename _Enabler2 = void, typename _Enabler3 = void>
struct Converter;
}
}
#define _IF_STRING_CONVERTIBLE_(T) typename std::enable_if<::et::IsConvertibleToString<T>::value>::type
The UTF-8 CPP can be obtained from here: link .
I'm still interested in suggestions, but I'm 95% sure the that wchar_t
is the cuplrit.
I think you may be missing a template<> somewhere...
template<>
struct Converter<From, Type> : public std::true_type
{
inline Type operator()(const From& from, const std::locale& locale) const;
};
// missing template<> here ?? As is, this is not ANSI compliant
Type Converter<From, T>::operator()(const From& from, const std::locale& locale) const { return Type(); }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.