c++ - 调用我的模板操作符 << 只有在没有找到其他操作符时

标签 c++ templates

我想通过 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/

相关文章:

c++ - 可变参数模板和 Alexandrescu 元组实现

c++ - 如何将 Ubuntu 上的应用程序交叉编译到 Windows

c++ - 有什么方法可以更轻松地使用函数指针作为模板参数?

c++ - 如何从模板签名创建 boost::function

c++ - 模板方法何时可以使用稍后定义的函数,而无需前向声明?

C# 自定义项目模板

c++ - 继承类模板有好处吗?

c++ - 如何从同样具有 'main' 的 .cpp 源文件中链接函数?

javascript - 如何使用下划线模板渲染 JS 对象?

c++ - 具有不完全整数类型的结构和枚举