我对SFINAE
或tag dispatching
之类的模板概念非常陌生,并一直在阅读一些文章和示例,这些文章和示例对我的方法没有帮助。因此,如果有人可以帮助我,我将不胜感激。
我的目标是拥有1个单个解析函数,该函数将在将数据转发给其他函数以根据模板T
类型进行特定解析之前进行一些处理。
在所附的代码中,这是我想要的行为。我在这里使用if constexpr
,不幸的是,这是C ++ 17功能,在我使用的C ++版本中不可用。
我认为,出于这个目的,template specialization
看起来是最好的解决方案,但这不是我想要的。
我认为,tag dispatching
会是一个很好的方向,但是我不确定在使用自定义类型时如何使用type_traits
来实现这一点,因为总是有2个选项,{ {1}}或true_type
,但是在下面的代码中,我遇到了3种情况,可能会有更多的情况。
对于某些示例或指导,我将不胜感激,这是执行我所寻找的最佳方法。即使读一些文章也很棒。
谢谢!
工作代码示例:
false_type
答案 0 :(得分:3)
标签分配将使此处变得更容易:
struct Base { int id; };
struct Foo : Base { int fooValue; };
struct Bar : Base { int barValue; };
template <typename T> struct Tag {};
std::shared_ptr<Foo> parse_impl(Tag<Foo>, const std::string& data) { return make_shared<Foo>(); }
std::shared_ptr<Bar> parse_impl(Tag<Bar>, const std::string& data) { return make_shared<Bar>(); }
std::shared_ptr<std::vector<Foo>> parse_impl(Tag<std::vector<Foo>>, const std::string& data)
{
return make_shared<std::vector<Foo>>();
}
template <typename T>
std::shared_ptr<T> parse(const std::string& data)
{
if (data.empty())
return nullptr;
return parse_impl(Tag<T>{}, data);
}
答案 1 :(得分:2)
为什么不只为parseFoo
,parseBar
和parseFoos
提供模板专业化,然后只从静态parse
函数内部调用模板方法:>
//parseT replaces parseFoo, parseBar, parseFoos
template<typename T>
std::shared_ptr<T> parseT(const std::string & data);
// provide implementaiton for Foo, Bar and vector<Foo>
template<>
std::shared_ptr<Foo> parseT<Foo>(const std::string & data) {
return std::make_shared<Foo>();
}
template<>
std::shared_ptr<Bar> parseT<Bar>(const std::string & data) {
return std::make_shared<Bar>();
}
template<>
std::shared_ptr<std::vector<Foo>> parseT<std::vector<Foo>>(const std::string & data) {
return std::make_shared<std::vector<Foo>>();
}
template <typename T>
std::shared_ptr<T> parser(const std::string & data) {
std::shared_ptr<T> result = nullptr;
if (data.empty())
return result;
result = std::make_shared<T>();
result = parseT<T>(data); // simple call to template function
return result;
}
编辑:糟糕,阅读得不够正确,现在我看到的不是您想要的(尽管不确定为什么,这似乎是我的最佳选择:D)。无论如何,如果您想按照以下代码的方式使用标签分发功能(同样,由于parser
函数的另一个模板参数,IMO不太好):
struct FooTag {};
struct BarTag{};
struct FoosTag{};
std::shared_ptr<Foo> parseT(const std::string & data, FooTag) {
return std::make_shared<Foo>();
}
std::shared_ptr<Bar> parseT(const std::string & data, BarTag) {
return std::make_shared<Bar>();
}
std::shared_ptr<std::vector<Foo>> parseT(const std::string & data, FoosTag) {
return std::make_shared<std::vector<Foo>>();
}
// template version
template <typename T, typename Tag>
std::shared_ptr<T> parser(const std::string & data) {
std::shared_ptr<T> result = nullptr;
if (data.empty())
return result;
result = std::make_shared<T>();
result = parseT(data, Tag());
return result;
}
如果您不需要额外的模板参数,则可以让用户在Foo
和Bar
之内以及其他任何地方提供标记类,但是当您拥有{{1 }}个vector
:
Foo
另一个编辑:
您可以为Tag创建一个模板类,以便摆脱// Tag is now a nested class
class Foo {
public:
struct Tag{};
};
class Bar {
public:
struct Tag{};
};
std::shared_ptr<Foo> parseT(const std::string & data, Foo::Tag) {
return std::make_shared<Foo>();
}
std::shared_ptr<Bar> parseT(const std::string & data, Bar::Tag) {
return std::make_shared<Bar>();
}
template <typename T>
std::shared_ptr<T> parser(const std::string & data) {
std::shared_ptr<T> result = nullptr;
if (data.empty())
return result;
result = std::make_shared<T>();
result = parseT(data, T::Tag()); // tag is now inside of template parameter
return result;
}
函数中的多余模板参数
parser