【问题标题】:c2064 compilation error on updating from msvc v100 to v140 platform toolset从 msvc v100 更新到 v140 平台工具集时出现 c2064 编译错误
【发布时间】:2017-06-12 15:13:47
【问题描述】:

我继承了一个必须从 MSVC 平台工具集 v100 更新到 v140 的项目。它适用于即将发布的 Archicad。一切都很好,除了当我将平台工具集设置为 140 时,我的模板函数之一失灵并出现编译错误:

C2064 术语不计算为采用 2 个参数的函数

在此之后我收到了同一行的警告:

类没有定义一个“operator()”或用户定义的转换运算符到一个指向函数的指针或函数的引用,它接受适当数量的参数

IDE 指向的这个块中的 return 语句:

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.
}

我有几个这样的专业:

CONVERTER(API_Guid, GS::Guid, from, locale)
{
   (void)locale;    // It gets optimized away
   return APIGuid2GSGuid(from);
}

CONVERTER 定义为:

#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

转换器类的operator() 过载。我尝试了一些解决方法,例如直接定义 Convert 函数,但是这样我就遇到了链接器错误。

有人能指出我错过了什么吗?我用旧的平台工具集编译它没有问题。微软是否在新版本中进行了某些更改?


我已对转换器标头进行沙盒处理,并缩小了范围。将未注释的行标记为编译失败,并抛出之前提到的编译错误(C2064)。

这是精简后的 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;
        }

    }
}

如果有人感兴趣,这里是 Declarations.hpp 以便于复制:

#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

UTF-8 CPP 可以从这里获得:link

我仍然对建议感兴趣,但我 95% 确定 wchar_t 是cuplrit。

【问题讨论】:

  • 你能在你的问题中标记那些警告的代码行吗?如果你能准备一个complete, minimal file to reproduce the issue 会很有帮助。
  • 另外,请花点时间阅读the help pages,尤其是名为“What topics can I ask about here?”和“What types of questions should I avoid asking?”的部分。也请take the tour 阅读how to ask good questions。如果你打算在 SO 上停留更长时间,每一方都会从中受益。
  • MS 正试图使其编译器更接近 ANSI 标准。自 VC6 以来的每个版本的编译器都有一小部分他们称之为“重大更改”,这使他们更接近这个目标。
  • @ArturR.Czechowski 我已经标记了编译失败的确切行。
  • 我知道认为 VC 6 不符合标准很酷,但考虑到 VC 6 是在 C++98 标准化之前发布的,这有点愚蠢。是的,微软正在努力提高其编译器的标准合规性,就像所有其他供应商一样。

标签: c++ templates visual-c++ visual-studio-2015 macros


【解决方案1】:

我认为您可能在某处缺少模板...

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(); }

【讨论】:

  • 这也是我发现的第一件事,但我对这个答案有几个问题。首先,您没有真正解释在哪里缺少的template&lt;&gt;在他的代码中。问题是CONVERTER宏的定义;也许您应该在某处提及以使答案更清楚?其次,你还没有实际测试过这个来确认它确实是答案,所以我觉得在评论中提出这种类型的建议会更合适。
  • 我已经在你指出的地方添加了可能缺少的模板,}; \ template&lt;&gt; \ Type Converter&lt;.. 我收到 C2910 错误,说:operator () : cannot be explicitspecialized。
  • 也做了一些研究,link 在帖子中引用了 C++ Templates the comple guide,其中指出 对于类专业化,成员的任何定义函数必须定义为“普通”成员函数。我的代码行为是这样的。
  • 我注意到了一些事情。 inline 关键字应该在函数的实现之前。而我错了。删除模板。如此处所示:docs.microsoft.com/fr-fr/cpp/error-messages/compiler-errors-2/…
  • 在尝试直接定义转换函数时,内联的位置可能是链接错误的根源?
猜你喜欢
  • 2016-01-14
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 2021-07-19
  • 1970-01-01
  • 1970-01-01
  • 2019-08-15
相关资源
最近更新 更多