引数がRef*の場合とそうでない場合で処理をわけるテンプレート関数
自作クラスでテンプレート関数を作り、
引数valueがRef*の場合とそうでない場合で処理を変えたいと思っています。
valueの型がint,float,double,std::string,boolなどの場合は_valueMapに格納し、
Ref*の場合は_objectMapに格納するようにしたいです。
class MyClass : public cocos2d::Ref
{
private:
cocos2d::ValueMap _valueMap;
cocos2d::Map<std::string, cocos2d::Ref*> _objectMap;
public:
template <typename T>
inline void addValue(T value, const std::string& key);
template <typename T>
inline T getValue(const std::string& key);
}
template <typename T>
inline void MyClass::addValue(T value, const std::string& key)
{
_valueMap[key] = value;
}
tempalte <>
inline void MyClass::addValue(cocos2d::Ref* value, const std::string& key)
{
if (value) {
_objectMap.insert(key, value);
}
}
ところがこのコードだと、RefのサブクラスであるNodeや、その他の自作クラスのポインタをvalueとして渡したときに、特殊化した関数が呼ばれず、_valueMapのほうに格納されてしまいます。
関数を呼ぶときにaddValue<Ref*>とすれば大丈夫なのですが、書き忘れが怖いです。
Ref*の場合とそれ以外で関数を分けるしかないのでしょうか。
編集:
回答ありがとうございます。
Ref*の他に、TがVec2の場合の特殊化をするにはどうしたらいいのでしょうか。
template <>
inline void addValue<cocos2d::Vec2>(const cocos2d::Vec2& value, const std::string& key)
{
_vec2Map[key] = value;
}
と書いたらNo function template matches function template specializationというエラーになりました。
enable_ifの条件を追加して、Vec2の場合にも非テンプレート関数を書くしかないのでしょうか。
編集:
解決しました。
MyClass.h
class MyClass : public cocos2d::Ref
{
std::unordered_map<std::string, cocos2d::Vec2> _vec2Map;
std::unordered_map<std::string, cocos2d::Size> _sizeMap;
std::unordered_map<std::string, cocos2d::Rect> _rectMap;
cocos2d::ValueMap _valueMap;
cocos2d::Map<std::string, cocos2d::Ref*> _objectMap;
public:
template <typename T,
typename std::enable_if<!std::is_convertible<T, cocos2d::Ref*>::value,
std::nullptr_t>::type = nullptr>
inline void addValue(T value, const std::string& key)
{
CCLOG("%s", __PRETTY_FUNCTION__);
_valueMap[key] = value;
}
void addValue(cocos2d::Ref* value, const std::string& key)
{
CCLOG("%s", __PRETTY_FUNCTION__);
if (value) {
_objectMap.insert(key, value);
}
}
};
#include "MyClass_Private.h"
MyClass_Private.h
#include "MyClass.h"
template <>
inline void MyClass::addValue<cocos2d::Vec2,nullptr>
(cocos2d::Vec2 value, const std::string& key)
{
_vec2Map[key] = value;
}
template <>
inline void MyClass::addValue<cocos2d::Size,nullptr>
(cocos2d::Size value, const std::string& key)
{
_sizeMap[key] = value;
}
template <>
inline void MyClass::addValue<cocos2d::Rect,nullptr>
(cocos2d::Rect value, const std::string& key)
{
_rectMap[key] = value;
}