这是我的定义:
template<typename ... TL>
struct TemplatedType { };
template<typename ... TL>
std::istream& operator>>(std::istream& is, TemplatedType<TL ...> & sp)
{
// do stuff
return is;
}
用法:
std::istringstream iss("I'd like some pancakes, please");
TemplatedType<int> a;
iss >> a;
它的效果很好,但是我希望将模板化的参数作为r值引用:
template<typename ... TL>
std::istream& operator>>(std::istream& is, const TemplatedType<TL && ...> & sp) {...}
然后,编译器开始大喊:
C2678二进制'&gt;&gt;':找不到运算符,它采用左手操作数 'std :: istringstream'类型(或没有可接受的转换)
问题出在哪里?
动机:
我想创建一个可以这种方式使用的split
函数:
std::istringstream iss("alpha:=10/50.1");
std::string x;
int y;
double z;
iss >> split(x, ':', '=', y, '/', z); // sets x=alpha, y=10, z=50.1
因此该函数需要能够接收l值和r值引用。
答案 0 :(得分:2)
有趣的问题。
Jarod42解释了问题所在:如果定义TemplatedType<int> a;
,则可以匹配
template<typename ... TL>
std::istream& operator>>(std::istream& is,
const TemplatedType<TL ...> & sp)
但无法匹配
template<typename ... TL>
std::istream& operator>>(std::istream& is,
const TemplatedType<TL & ...> & sp)
因为您有int
并且需要int&
。
但是如何开始工作
iss >> split(x, ':', '=', y, '/', z);
嗯......我想你可以在std::tuple
TemplatedType
template <typename ... TL>
struct TemplatedType
{ std::tuple<TL...> t; };
所以split()
(我已将其重命名为mySplit()
)只是变成
template <typename ... TL>
TemplatedType<TL...> mySplit (TL && ... al)
{ return { std::forward_as_tuple(al...) }; }
和
mySplit(x, ':', '=', y, '/', z);
其中x
为std::string
,y
为int
而z
为double
,您获得TemplatedType<std::string &, char, char, int &, char, double &>
}。
您可以编写一个调用第一个辅助函数的operator<<()
template <typename ... TL>
std::istream & operator>> (std::istream & is,
TemplatedType<TL...> const & sp)
{
myHelper1(is, sp, std::index_sequence_for<TL...>{});
return is;
}
和sp
中包含的元组中的第一个辅助函数提取元素,并调用第二个辅助函数
template <typename ... TL, std::size_t ... IL>
void myHelper1 (std::istream & is,
TemplatedType<TL...> const & sp,
std::index_sequence<IL...> const &)
{ myHelper2(is, std::get<IL>(sp.t)...); }
第二个辅助函数稍微复杂一些。
它是一个递归的函数集,每次调用都会消耗一个/两个元素。
首先,地面(终端)案例
void myHelper2 (std::istream &)
{ }
然后是具有以下常量std::string
的特殊char
情况,分隔符(没有分隔符,如果您只是编写is >> s
,则会获得is
中包含的完整字符串})
template <typename ... TS>
void myHelper2 (std::istream & is, std::string & s, char const & delim,
TS && ... ts)
{
std::getline(is, s, delim);
myHelper2(is, std::forward<TS>(ts)...);
}
接下来在您的示例中接收常量字符(例如:
,=
和/
的版本;但第一个字符串作为字符串的分隔符使用)并丢弃来自char
的{{1}}(如果需要,请检查丢弃的char是否与char相同)
is
最后一般情况,接收通用(类型template <typename ... TS>
void myHelper2 (std::istream & is, char const ch, TS && ... ts)
{
char ch2;
is >> ch2;
// check if `ch` == `ch2`? exception otherwise?
myHelper2(is, std::forward<TS>(ts)...);
}
)引用
T
以下是一个完整的例子。
从C ++ 14开始工作,因为{+ 1}}和template <typename T, typename ... TS>
void myHelper2 (std::istream & is, T & t, TS && ... ts)
{
is >> t;
myHelper2(is, std::forward<TS>(ts)...);
}
是在C ++ 14中引入的。但是如果你想要一个C ++ 11解决方案,为他们写一个sobstitute很简单
std::index_sequence
答案 1 :(得分:0)
理论上如果TemplatedType
的实现方式与std:tuple
相同(或者这是一个元组),并且所有成员类型都存在>>
个运算符。
例如:
#include <istream>
#include <iostream>
#include <tuple>
namespace detail {
template<std::size_t... Is>
struct seq { };
template<std::size_t N, std::size_t... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };
template<std::size_t... Is>
struct gen_seq<0, Is...> : seq<Is...> { };
template<typename T, typename F, std::size_t... Is>
void for_each(T&& t, F&& f, seq<Is...>)
{
auto l = { (f(std::get<Is>(t)), 0)... };
}
template<typename... Ts, typename F>
void tuple_for_each(std::tuple<Ts...>& t, F&& f)
{
for_each(t, std::forward<F>(f), detail::gen_seq<sizeof...(Ts)>());
}
class deserializer {
deserializer(const deserializer&) = delete;
deserializer& operator=(const deserializer&) = delete;
public:
constexpr deserializer(std::basic_istream<char>& is) noexcept:
is_(is)
{}
template<typename any_type>
void operator()(any_type& val) {
is_ >> val;
}
private:
std::basic_istream<char>& is_;
};
} // namespace detail
template<typename...__tl>
std::basic_istream<char>& operator >> (std::basic_istream<char>& s, std::tuple<__tl...> &out)
{
detail::tuple_for_each( out, detail::deserializer(s) );
return s;
}
int main(int argc, const char** argv)
{
std::cout<< "Please input a digit" << std::endl;
std::tuple<int> int_only_tuple;
std::cin >> int_only_tuple;
std::cout<< "A digit: " << std::get<0>(int_only_tuple) << std::endl;
std::cout<< "Please input two strings" << std::endl;
std::tuple<std::string, std::string> in;
std::cin >> in;
std::cout << "First string: " << std::get<0>(in) << std::endl;
std::cout<< "Second string: " << std::get<1>(in) << std::endl;
return 0;
}
另见: