我正在boost::lexical_cast
上使用std::pair<int, int>
。
#include <iostream>
#include <utility>
#include <boost/lexical_cast.hpp>
namespace my
{
// When my_pair is a user defined type, this program compiles
// and runs without any problems.
// When declaring my_pair as an alias of std::pair<int, int>,
// it fails to compile
/*
struct my_pair
{
int first;
int second;
};
*/
using my_pair = std::pair<int, int>;
std::istream& operator>>(std::istream& stream, my_pair& pair)
{
stream >> pair.first;
stream >> std::skipws;
stream >> pair.second;
return stream;
}
}
int main()
{
my::my_pair p = boost::lexical_cast<my::my_pair>("10 10");
std::cout << p.first << " " << p.second << std::endl;
return 0;
}
如果我理解正确,为了使ADL工作,运营商&gt;&gt;必须与my_pair位于同一名称空间中,所以std。
这样做会导致未定义的行为,因为我会在命名空间std。
中添加函数我想避免继承,例如struct my_pair : std::pair<int, int>
。
这个问题的解决方案是什么?
我在OS X上使用clang ++ - 3.6。
答案 0 :(得分:7)
您可以在流上重载(以某种方式对其进行标记),而不是对要传输的值进行ADL挂钩:
int main() {
std::map<int, std::string> standback { { 42, "I'm gonna try" }, { 1729, "science" } };
streaming::tag_ostream out = std::cout;
for (auto& entry : standback)
out << entry << "\n";
}
这样,您可以在您控制的命名空间上进行ADL挂钩。您可以使标记更通用(想想auto out = streaming::tag(std::cout)
)。
现在,一个简单的实现可能看起来像
namespace streaming {
template <typename T>
struct tag : std::reference_wrapper<T> {
using std::reference_wrapper<T>::reference_wrapper;
};
using tag_ostream = tag<std::ostream>;
template <typename T1, typename T2>
static inline tag_ostream operator<<(tag_ostream os, std::pair<T1, T2> const& p) {
os.get() << "std::pair{" << p.first << ", " << p.second << "}";
return os;
}
template <typename Other>
static inline tag_ostream operator<<(tag_ostream os, Other const& o) {
os.get() << o;
return os;
}
}
查看 Live On Coliru ,其中会打印:
std::pair{42, I'm gonna try}
std::pair{1729, science}
答案 1 :(得分:2)
这样做会导致未定义的行为,因为我会在命名空间std。
中添加函数我想避免继承,例如struct my_pair:std :: pair。
我想说“继承”,但你不予理会......
您可以使用封装,只需在struct my_pair
{
std::pair<int,int> value;
// TODO: add any access interface here
};
std::istream& operator>>(std::istream& stream, my_pair& pair)
{
stream >> pair.value.first;
stream >> std::skipws;
stream >> pair.value.second;
return stream;
}
上添加另一种强类型(但在这种简单的情况下,您可能最好使用自定义结构 - 您的注释代码):
Public Class Form2
Private WithEvents pd As New Printing.PrintDocument
Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Using bmp As New Bitmap(Form1.pb1.Width, Form1.pb1.Height)
Form1.panel1.DrawToBitmap(bmp, New Rectangle(0, 0, Form1.pb1.Width, Form1.pb1.Height))
e.Graphics.DrawImage(bmp, e.MarginBounds)
End Using
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
PrintDocument1.Print()
End Sub
End Class
事实上,你可能应该这样做,因为std :: pair更像是一个构建块,而不是用来表示语义信息的东西(而不是那些应该直接打印到的东西)一条小溪)。
答案 2 :(得分:2)
我知道你说你不想要这个,但我绝对会使用继承:
#include <iostream>
#include <utility>
#include <boost/lexical_cast.hpp>
namespace my
{
struct my_pair : std::pair<int, int> {};
std::istream& operator>>(std::istream& stream, my_pair& pair)
{
stream >> pair.first;
stream >> std::skipws;
stream >> pair.second;
return stream;
}
}
int main()
{
my::my_pair p = boost::lexical_cast<my::my_pair>("10 10");
std::cout << p.first << " " << p.second << std::endl;
}
您的my::my_pair
字面上是-a std::pair<int, int>
;你只需要它在你自己的命名空间中成为一个独特的类型。这就是继承的目的。
我刚刚离开这里,以表明这是多么容易,并解释为什么我认为你应该这样做。