我想通过 toString 成员函数打印对象的状态,但我想通过 String::toString(var)
调用它.但我只想对没有 operator<<
的对象执行此操作定义。
我的尝试如下。
我有模板 operator<<
哪个电话toString
, 但我希望只有在没有其他合适的情况下才会考虑这个运算符 operator<<
已被发现。我显然错了:)
#include <iostream>
#include <sstream>
struct WithToString
{
std::string toString()
{ return std::string ("foo") ; }
};
struct WithoutToString {};
struct String
{
template <typename T>
static std::string toString(T & var)
{
std::stringstream s;
s << var;
return s.str();
}
};
template <typename T>
std::ostream & operator<<(std::ostream & s, T & var)
{
s << var.toString();
return s;
}
int main(int argc, char *argv[])
{
int i = 5;
std::cout << String::toString(i); //fine, prints 5
WithToString w;
std::cout << String::toString(w); //fine, prints foo
// WithoutToString ws;
// std::cout << String::toString(ws); //fine - give "toString is not a member" error
// const char * s = "bar";
// std::cout << String::toString(s); //error - operator << is ambiguous
// std::string s = "bar";
// std::cout << String::toString(s); //error - toString is not a member
return 0;
}
如何实现这种行为?
编辑
这是我的另一次尝试,但再次失败,字符串和字符 *
template <class Type, class V>
class HasOperatorShiftLeft
{
template <typename T, T> struct TypeCheck;
typedef char Yes;
typedef long No;
template <typename T> struct ToString
{
typedef std::ostream & (T::*fptr)(V);
};
template <typename T> static Yes HasOpShift(TypeCheck< typename ToString<T>::fptr, &T::operator<< >*);
template <typename T> static No HasOpShift(...);
public:
static bool const value = (sizeof(HasOpShift<Type>(0)) == sizeof(Yes));
};
template <typename T, int A>
struct toStringStr{};
template <typename T>
struct toStringStr<T,1>
{
static std::string toString(T & var)
{
std::stringstream s;
s << var;
return s.str();
}
};
template <typename T>
struct toStringStr<T,0>
{
static std::string toString(T & var)
{
return var.toString();
}
};
template <typename T>
std::string toString(T & var)
{
return toStringStr<T,HasOperatorShiftLeft<std::ostream,T>::value>::toString(var);
}
编辑 我的最新尝试作为答案发布,因为我认为它有效
最佳答案
这实际上很容易,尽管如评论中所述那样做很愚蠢。使用 C++11:
template<class T>
auto operator<<(std::ostream& os, T const& val)
-> decltype(os << val.toString())
{
return os << val.toString();
}
这个函数只有在decltype(..)
里面有内容的情况下才会存在是一个有效的表达式。现在只需将所有内容流式传输到 std::ostream&
中收工吧。如果一个类型同时具有 toString
和重载 operator<<
对于 std::ostream&
,好吧,艰难。您将收到“对重载 operator<<
的模糊调用”错误。
对于 C++03,还有另一种选择。由于您似乎有点不喜欢自由函数,我假设您喜欢接口(interface)。因此,给自己一个Streamable
带有 virtual std::string toString() const = 0
的基类方法和重载 operator<<
仅此而已。 Presto,你有operator<<
对于实现该接口(interface)的所有类!
struct Streamable{
virtual std::string toString() const = 0;
};
std::ostream& operator<<(std::ostream& os, Streamable const& s){
return os << s.toString();
}
或者您甚至可以深入到元级别以摆脱无用的虚函数调用:
template<class D>
struct Streamable{
std::string toString() const{
return static_cast<D const&>(*this).toString();
}
};
template<class D>
std::ostream& operator<<(std::ostream& os, Streamable<D> const& s){
return os << s.toString();
}
// example:
struct Blub
: public Streamable<Blub>
{
// implement toString() ...
};
关于c++ - 调用我的模板操作符 << 只有在没有找到其他操作符时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9198443/