重载运算符中的类型不匹配(编写管道)
Type mismatch in overloaded operator (writing pipelines)
只需testing/learning在C++中重载|
运算符编写管道,如下程序
编译失败:
invalid operands to binary expression candidate template ignored:
...
could not match 'bitset' against 'vector'
似乎编译器正在尝试使用标准 |定义。
该代码适用于显式调用和显式类型参数集。
// g++ -std=c++11 Pipeline.cpp
#include <iostream>
#include <vector>
// ..............................................................
// ..............................................................
std::string dup (std::string s) {
return s + s;
}
// ..............................................................
// ..............................................................
template <typename TI, typename TO>
std::vector<TO> operator | (const std::vector<TI> & in, std::function<TO(TI)> f) {
std::vector<TO> out;
for (auto i : in) {
out.push_back ( f(i) );
}
return out;
}
// ..............................................................
// ..............................................................
int main () {
std::cout << " hello " << std::endl;
std::vector<std::string> vs = {"one", "two", "three", "four", "five"};
auto res = vs | dup;
// OK: vector<string> res = operator|<string,string> (vs, dup);
for (auto s : res) { std::cout << s << std::endl; }
} // ()
完整的错误信息:
Pipeline.cpp:29:17: error: invalid operands to binary expression
('std::vector<std::string>' and 'std::string (*)(std::string)')
auto res = vs | dup;
~~ ^ ~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/bitset:1045:1: note:
candidate template ignored: could not match 'bitset' against 'vector'
operator|(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT
^
Pipeline.cpp:13:17: note: candidate template ignored: could not match
'function<type-parameter-0-1 (type-parameter-0-0)>' against
'std::__1::basic_string<char> (*)(std::__1::basic_string<char>)'
std::vector<TO> operator | (const std::vector<TI> & in, std::function<TO...
^
1 error generated.
模板参数推导不查看隐式转换。函数指针不是 std::function
,因此编译器无法推断出用什么模板参数来实例化您的 operator|
。通常,std::function<...>
,其中 ...
包含模板参数,不是接受任意函数或函数对象的正确方法。
相反,接受函子的任何类型:
template <typename TI, typename F>
/* something */ operator | (const std::vector<TI> & in, F f)
然后找出return类型。
return 类型是 std::vector
,其值类型是 return 通过对 in
的元素调用 f
得到的类型 - 在换句话说,decltype(f(in[0]))
。但是,f
可以 return 引用类型,并且在这些情况下您确实希望向量的值类型是所引用的类型。使用 std::decay
(或 std::remove_reference
)去除任何参考性:
template <typename TI, typename F>
auto operator | (const std::vector<TI> & in, F f) -> std::vector<typename std::decay<decltype(f(in[0]))>::type> {
std::vector<typename std::decay<decltype(f(in[0]))>::type> out;
/*...*/
}
Demo.
T.C 的类似解决方案。
template <typename CONT, typename F> // types: container , function
auto operator | (const CONT & a, F f) {
// find out input type and output type
using TI = typename CONT::value_type;
TI aux;
using TO = decltype(f(aux));
// do the task
vector<TO> res;
for (auto & i : a) {
res.push_back( f(i) );
}
return res;
}
编辑
完成 "experimental" 代码。将运算符更改为
是 ==
:变换,!=
过滤器,和 >>=
reduce/visit,因此
避免在 vs == dup != lengthy != contains == length >>= add;
等表达式中使用括号(我们需要 transform 和 filer 具有相同的优先级,而 reduce 具有较低的优先级)。不知道这是否会对使用它们的其他表达式造成附带问题。
// g++ -std=c++1y Pipeline.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// ..............................................................
// transform
// ..............................................................
template <typename CONT, typename F>
auto operator == (const CONT & a, F f) {
using IT = typename CONT::value_type;
IT aux;
using OT = decltype(f(aux));
vector<OT> res;
for (auto & i : a) {
res.push_back( f(i) );
}
return res;
}
// ..............................................................
// filter
// ..............................................................
template <typename CONT, typename F>
auto operator != (const CONT & a, F f) {
using IT = typename CONT::value_type;
IT aux;
vector<IT> res;
for (auto & i : a) {
if (f(i)) res.push_back( i );
}
return res;
}
// ..............................................................
// reduce / visit
// ..............................................................
template <typename CONT, typename F>
auto operator >>= (const CONT & a, F f) {
for (auto & i : a) {
f(i);
}
return f;
}
// ..............................................................
// ..............................................................
int main () {
vector<string> vs = {"one", "two", "three", "four", "five"};
int sum = 0;
auto dup = [] (const string &s) -> string { return s+s; };
auto lengthy = [] (const string &s) -> bool { return s.length()>6; };
auto contains = [] (const string &s) -> bool { return s.find('f') != string::npos; };
auto length = [] (const string &s) { return s.length(); };
auto add = [&sum] (int i) { sum += i;};
// == transform
// != filter
// >>= reduce / visit
vs == dup != lengthy != contains == length >>= add;
cout << sum << endl;
auto res1 = vs == dup != lengthy != contains;
for (auto & s : res1) { cout << s << endl; }
} // ()
只需testing/learning在C++中重载|
运算符编写管道,如下程序
编译失败:
invalid operands to binary expression candidate template ignored: ... could not match 'bitset' against 'vector'
似乎编译器正在尝试使用标准 |定义。 该代码适用于显式调用和显式类型参数集。
// g++ -std=c++11 Pipeline.cpp
#include <iostream>
#include <vector>
// ..............................................................
// ..............................................................
std::string dup (std::string s) {
return s + s;
}
// ..............................................................
// ..............................................................
template <typename TI, typename TO>
std::vector<TO> operator | (const std::vector<TI> & in, std::function<TO(TI)> f) {
std::vector<TO> out;
for (auto i : in) {
out.push_back ( f(i) );
}
return out;
}
// ..............................................................
// ..............................................................
int main () {
std::cout << " hello " << std::endl;
std::vector<std::string> vs = {"one", "two", "three", "four", "five"};
auto res = vs | dup;
// OK: vector<string> res = operator|<string,string> (vs, dup);
for (auto s : res) { std::cout << s << std::endl; }
} // ()
完整的错误信息:
Pipeline.cpp:29:17: error: invalid operands to binary expression
('std::vector<std::string>' and 'std::string (*)(std::string)')
auto res = vs | dup;
~~ ^ ~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/bitset:1045:1: note:
candidate template ignored: could not match 'bitset' against 'vector'
operator|(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT
^
Pipeline.cpp:13:17: note: candidate template ignored: could not match
'function<type-parameter-0-1 (type-parameter-0-0)>' against
'std::__1::basic_string<char> (*)(std::__1::basic_string<char>)'
std::vector<TO> operator | (const std::vector<TI> & in, std::function<TO...
^
1 error generated.
模板参数推导不查看隐式转换。函数指针不是 std::function
,因此编译器无法推断出用什么模板参数来实例化您的 operator|
。通常,std::function<...>
,其中 ...
包含模板参数,不是接受任意函数或函数对象的正确方法。
相反,接受函子的任何类型:
template <typename TI, typename F>
/* something */ operator | (const std::vector<TI> & in, F f)
然后找出return类型。
return 类型是 std::vector
,其值类型是 return 通过对 in
的元素调用 f
得到的类型 - 在换句话说,decltype(f(in[0]))
。但是,f
可以 return 引用类型,并且在这些情况下您确实希望向量的值类型是所引用的类型。使用 std::decay
(或 std::remove_reference
)去除任何参考性:
template <typename TI, typename F>
auto operator | (const std::vector<TI> & in, F f) -> std::vector<typename std::decay<decltype(f(in[0]))>::type> {
std::vector<typename std::decay<decltype(f(in[0]))>::type> out;
/*...*/
}
Demo.
T.C 的类似解决方案。
template <typename CONT, typename F> // types: container , function
auto operator | (const CONT & a, F f) {
// find out input type and output type
using TI = typename CONT::value_type;
TI aux;
using TO = decltype(f(aux));
// do the task
vector<TO> res;
for (auto & i : a) {
res.push_back( f(i) );
}
return res;
}
编辑
完成 "experimental" 代码。将运算符更改为
是 ==
:变换,!=
过滤器,和 >>=
reduce/visit,因此
避免在 vs == dup != lengthy != contains == length >>= add;
等表达式中使用括号(我们需要 transform 和 filer 具有相同的优先级,而 reduce 具有较低的优先级)。不知道这是否会对使用它们的其他表达式造成附带问题。
// g++ -std=c++1y Pipeline.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// ..............................................................
// transform
// ..............................................................
template <typename CONT, typename F>
auto operator == (const CONT & a, F f) {
using IT = typename CONT::value_type;
IT aux;
using OT = decltype(f(aux));
vector<OT> res;
for (auto & i : a) {
res.push_back( f(i) );
}
return res;
}
// ..............................................................
// filter
// ..............................................................
template <typename CONT, typename F>
auto operator != (const CONT & a, F f) {
using IT = typename CONT::value_type;
IT aux;
vector<IT> res;
for (auto & i : a) {
if (f(i)) res.push_back( i );
}
return res;
}
// ..............................................................
// reduce / visit
// ..............................................................
template <typename CONT, typename F>
auto operator >>= (const CONT & a, F f) {
for (auto & i : a) {
f(i);
}
return f;
}
// ..............................................................
// ..............................................................
int main () {
vector<string> vs = {"one", "two", "three", "four", "five"};
int sum = 0;
auto dup = [] (const string &s) -> string { return s+s; };
auto lengthy = [] (const string &s) -> bool { return s.length()>6; };
auto contains = [] (const string &s) -> bool { return s.find('f') != string::npos; };
auto length = [] (const string &s) { return s.length(); };
auto add = [&sum] (int i) { sum += i;};
// == transform
// != filter
// >>= reduce / visit
vs == dup != lengthy != contains == length >>= add;
cout << sum << endl;
auto res1 = vs == dup != lengthy != contains;
for (auto & s : res1) { cout << s << endl; }
} // ()