我想做的是有两个函数模板:一个将字符串转换为 boost::optional<some integer type>
以及将字符串转换为 boost::optional<some enum type>
的一个。像这样的事情:
template<typename T> boost::optional<T> func(const std::string &s) { return boost::make_optional(std::stoi(s));}
template<typename T> boost::optional<T> func(const std::string &s) { return boost::make_optional(EnumMapper<T>::map_string_to_enum<T>(s));}
enum Color { Red, Blue, Green};
enum Direction { Up, Down, Left, Right};
auto a = func<int>("1234");
auto b = func<Color>("red");
auto c = func<Direction>("up");
我有一些工作可以为每种枚举类型进行专门化:
template<> boost::optional<Color> func(const std::string &s) { return boost::make_optional(EnumMapper<Color>::map_string_to_enum<Color>(s));}
template<> boost::optional<Direction> func(const std::string &s) { return boost::make_optional(EnumMapper<Direction>::map_string_to_enum<Direction>(s));}
但是对于几十个枚举来说,这看起来很丑陋并且容易出错。我有一种感觉,这就是类型特征的用途,但我发现的示例似乎都不适合我想做的事情。
编辑:感谢宋元耀!这有效:
#include <iostream>
#include <type_traits>
#include <string>
#include <boost/optional.hpp>
#include <cstdint>
enum Color {
Red,
Green,
Blue
};
enum Direction {
Up,
Down,
Left,
Right
};
template <typename T> struct EnumMapper { static boost::optional<T> map_string_to_enum(const std::string &s) = delete; };
template <> boost::optional<Color> EnumMapper<Color>::map_string_to_enum(const std::string &s) {
return Color::Green;
}
template <> boost::optional<Direction> EnumMapper<Direction>::map_string_to_enum(const std::string &s) {
return Direction::Right;
}
template<typename T>
typename std::enable_if<std::is_enum<T>::value, boost::optional<T>>::type
func(const std::string &s) {
return EnumMapper<T>::map_string_to_enum(s);
}
template<typename T>
typename std::enable_if<std::is_integral<T>::value, boost::optional<T>>::type
func(const std::string &s) {
return boost::make_optional<T>(std::stoi(s));
}
int
main() {
auto a = func<std::uint8_t>("123");
std::cout << static_cast<int>(*a) << std::endl;
auto b = func<Color>("Red");
std::cout << static_cast<int>(*b) << std::endl;
auto c = func<Direction>("Up");
std::cout << static_cast<int>(*c) << std::endl;
auto d = func<std::uint32_t>("2345");
std::cout << static_cast<int>(*d) << std::endl;
}
最佳答案
您可以使用类型特征 std::is_enum
,并应用 SFINAE .
template<typename T>
typename std::enable_if<std::is_enum<T>::value, boost::optional<T>>::type
func(const std::string &s) {
return boost::make_optional(EnumMapper<T>::map_string_to_enum<T>(s));
}
请注意,您还必须限制第一个重载的类型。您可以检查它是否为int
,或使用std::is_integral
。例如
template<typename T>
typename std::enable_if<std::is_same<T, int>::value, boost::optional<T>>::type
func(const std::string &s) {
return boost::make_optional(std::stoi(s));
}
关于C++ 11 : How to write 2 template functions that differ in their return type,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62910702/