Не может быть явно специализирован в Visual Studio 2017

#c #visual-studio #cocos2d-x #sfinae

#c #visual-studio #cocos2d-x #sfinae

Вопрос:

Я создаю игру, в которую можно играть на Mac и Windows с помощью cocos2d-x.

Сначала я написал код в Xcode, который можно было запускать на Mac.

Я получил сообщение об ошибке, когда перенес его в Windows и попытался выполнить сборку в Visual Studio 2017.

NRZNotification.h

 #include "cocos2d.h"

class NRZNotification : public cocos2d::Ref
{
protected:
    std::string _name;
    cocos2d::Ref* _sender;

    ...

    cocos2d::ValueMap _valueMap;
    cocos2d::Map<std::string, cocos2d::Ref*> _objectMap;
public:
    const std::stringamp; getName(){return _name;}
    cocos2d::Ref* getSender(){return _sender;}

    NRZNotification();
    virtual ~NRZNotification();
    static NRZNotification* create(const std::stringamp; name, Ref* sender);
    bool init(const std::stringamp; name, Ref* sender);

    ...

    template <typename T,
    typename std::enable_if<!std::is_convertible<T, cocos2d::Ref*>::value,
    std::nullptr_t>::type = nullptr>
    inline T getValue(const std::stringamp; key)
    {
        //CCLOG("%s", __PRETTY_FUNCTION__);
        return 0;
    }
    template <typename T,
    typename std::enable_if<std::is_convertible<T, cocos2d::Ref*>::value,
    std::nullptr_t>::type = nullptr>
    inline T getValue(const std::stringamp; key)
    {
        //CCLOG("%s", __PRETTY_FUNCTION__);
        return dynamic_cast<T>(_objectMap.at(key));
    }
};
#include "NRZNotification_Private.h"
  

NRZNotification_Private.h

 #include "NRZNotification.h"

...

#pragma mark - get value

template <>
inline int NRZNotification::getValue<int,nullptr>(const std::stringamp; key)
{
    if (_valueMap.find(key) == _valueMap.end()) {
        return 0;
    } else {
        return _valueMap.at(key).asInt();
    }
}
template <>
inline float NRZNotification::getValue(const std::stringamp; key)
{
    if (_valueMap.find(key) == _valueMap.end()) {
        return 0.0f;
    } else {
        return _valueMap.at(key).asFloat();
    }
}
template <>
inline double NRZNotification::getValue(const std::stringamp; key)
{
    if (_valueMap.find(key) == _valueMap.end()) {
        return 0.0;
    } else {
        return _valueMap.at(key).asDouble();
    }
}

...

  

Эти коды успешно выполнялись на Mac, но в Visual Studio 2017 вызов GetValue() выдал ошибку «не может быть явно специализирован».

GetValue() — это шаблон функции, и реализация разделяется в зависимости от того, является ли возвращаемое значение подклассом cocos2d::Ref .

Кроме того, специализация выполняется для int, float, string и т. Д.

Как я должен исправить этот код?

Я использую cocos2d-x 3.17.1.

Спасибо.

Комментарии:

1. Показать ошибку компилятора.

Ответ №1:

Я взял на себя смелость создать MCVE на основе вашего кода.

 #include <type_traits>

struct A {
    template<typename T, typename std::enable_if<!std::is_convertible<T, A>::value, int>::type = 0>
    T getValue() {
        return 1;
    }
    template<typename T, typename std::enable_if<std::is_convertible<T, A>::value, int>::type = 0>
    T getValue() {
        return T();
    }
};

template<>
inline int A::getValue<int, 0>() {
    return 3;
}

int main() {
    A a;
    return a.getValue<int>();
}
  

Действительно, MSVC 2019 не может его скомпилировать

 <source>(15): error C2910: 'A::getValue': cannot be explicitly specialized
  

В то время как GCC и clang компилируют его просто отлично. Живая демонстрация.

К счастью, решение простое — просто удалите явные параметры шаблона. В любом случае они излишни:

 template<>
inline int A::getValue() {
    return 3;
}
  

Итак, для вашего случая удалите <int,nullptr> из

 template <>
inline int NRZNotification::getValue<int,nullptr>(const std::stringamp; key)