简体   繁体   中英

c2064 compilation error on updating from msvc v100 to v140 platform toolset

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM