gpt4 book ai didi

c++ - 不同类型的特化

转载 作者:太空宇宙 更新时间:2023-11-04 14:37:59 25 4
gpt4 key购买 nike

谁能告诉我如何删除下面重复的特化?

#include <iostream>
#include <fstream>
#include <string>

struct Thing {
int a, b;
void load (std::istream& is) {is >> std::skipws >> a >> b;}
};

struct Object {
int a, b, c;
void load (std::istream& is) {is >> std::skipws >> a >> b >> c;}
};

template <typename...> struct PassArgs;

// General case.
template <typename First, typename... Rest>
struct PassArgs<First, Rest...> : PassArgs<Rest...> {
void operator()(std::istream& is, First& first, Rest&... rest) const {
is >> first;
PassArgs<Rest...>::operator()(is, rest...);
}
};

// Specialization for std::string needed.
template <typename... Rest>
struct PassArgs<std::string, Rest...> : PassArgs<Rest...> {
void operator()(std::istream& is, std::string& first, Rest&... rest) const {
while (std::getline (is, first) && first.empty());
PassArgs<Rest...>::operator()(is, rest...);
}
};

// Specialization for class Thing.
template <typename... Rest>
struct PassArgs<Thing, Rest...> : PassArgs<Rest...> {
void operator()(std::istream& is, Thing& first, Rest&... rest) const {
first.load(is);
PassArgs<Rest...>::operator()(is, rest...);
}
};

// Specialization for class Object, but is the exact same as that for Thing.
template <typename... Rest>
struct PassArgs<Object, Rest...> : PassArgs<Rest...> {
void operator()(std::istream& is, Object& first, Rest&... rest) const {
first.load(is);
PassArgs<Rest...>::operator()(is, rest...);
}
};


template <>
struct PassArgs<> {
void operator()(std::istream&) const {} // End of recursion.
};


int main() {}

一切正常,但有没有办法避免对所有具有 load(std::istream&) 函数的类进行特化(我的程序中有很多)。目前,我有 ThingObject 和许多其他类的特化,它们在它们的特化中都有相同的行。

顺便说一下,客户端是这样使用PassArgs的:

template <typename T, typename... Args>
T* create (std::istream& is, Args&... args) {
PassArgs<Args...>()(is, args...);
T* t = new T(args...);
// Do whatever with t;
return t;
}

最佳答案

大约有无数种方法可以做到这一点。这是其中之一。

首先是一个trait来检测是否有成员load()被称为。这是一种编写方法:

namespace details {    
template<class T>
auto has_load_impl(int)
-> decltype((void)std::declval<T&>().load(std::declval<std::istream&>()),
std::true_type());

template<class T>
std::false_type has_load_impl(...);

template<class T>
using has_load = decltype(has_load_impl<T>(0));
}

还有很多其他的方式来写这个特性。 Jonathan Wakely 的回答使用了 Walter Brown 的 void_t , 例如。或者你可以使用 std::experimental::is_detected .

接下来,编写一个加载单个参数的函数,根据 has_load 的结果进行调度.这是一种方法:

namespace details {
template<class T>
void do_load(std::istream& is, T& t, std::true_type /*has_load*/){
t.load(is);
}

template<class T>
void do_load(std::istream& is, T& t, std::false_type /*has_load*/){
is >> t;
}
}

template<class T>
void load(std::istream& is, T& t){
details::do_load(is, t, details::has_load<T>());
}

也可以省去 standalone 特征,SFINAE 直接在 do_load 中功能,如果你不需要其他地方的特征:

namespace details {
template<class T>
auto do_load(std::istream& is, T& t, int) -> decltype((void)t.load(is)){
t.load(is);
}

template<class T>
void do_load(std::istream& is, T& t, ...){
is >> t;
}
}

template<class T>
void load(std::istream& is, T& t){
details::do_load(is, t, 0);
}

根据需要为需要特殊处理的类型添加重载。

void load(std::istream& is, std::string& s){
while (std::getline (is, s) && s.empty());
}

最后,PassArgs本身可以简化为两行函数,使用braced-init-list中熟悉的包扩展技巧:

template<class... Args>
void PassArgs(std::istream& is, Args&... args){
using expander = int[];
(void)expander{0, (load(is, args), void(), 0)... };
}

Demo .

在上面,用户可以自定义load使用 ADL。或者,您可以制作 load类模板的成员函数 loader<T>相反,用户可以专门化 loader根据需要自定义负载:

template<class T>
struct loader {
static void load(std::istream& is, T& t) {
details::do_load(is, t, details::has_load<T>());
}
};

template<> struct loader<std::string>{
static void load(std::istream& is, std::string& s){
while (std::getline (is, s) && s.empty());
}
};

template<class... Args>
void PassArgs(std::istream& is, Args&... args){
using expander = int[];
(void)expander{0, (loader<T>::load(is, args), void(), 0)... };
}

关于c++ - 不同类型的特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31080336/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com