0
// First try this:

template <class T> T Read(istream& in) {
  T t;
  in >> t;
  return t;
}

// If there is no operator>>(istream&, T) try this: 

template <class T> T Read(istream& in) {
  return T (in);
}

// If there is no constructor T(istream&) try this:

template <class T> T Read(istream& in) {
  return T::OfStream (in);
}

// now fail.

这可以实施吗?

如果没有,有什么替代方案?

4

5 回答 5

8

您熟悉SFINAE的概念吗?使用此概念,您可以根据模板参数的任何属性在候选集中包含或排除函数模板。然而,正如 Alex Martelli 所说,您必须在签名中导致这种情况发生,而不是在方法的主体中。

这意味着您需要能够针对 T 类型的某些属性做出编译时决策,并使用该决策的结果来强制模板签名变为非法,这将在不引发编译的情况下将该模板从编译器的候选集中排除错误。

Boost 有两个库可以促进这一点:Boost.TypeTraits,它允许您询问诸如“T 是一个数组吗?”之类的问题。或“T 是指针吗?” 或“T 是 U 的子类吗?” 在编译时。Boost.EnableIf可以使用该查询的结果来排除函数(或不排除,根据需要)。

使用这些库的组合后,您可能能够实现您的目标。如果您使用特定的编译器,您也可以使用特定于编译器的扩展来获得类似的结果(如果您同意的话)。例如,使用 MSVC,您可能能够使用__if_exists关键字。根据您的简单示例与您真正想要做的事情的密切程度,一种方法可能比另一种更干净。

于 2009-10-29T02:50:15.317 回答
1

如前所述,这些都是模棱两可的。您应该研究 boostsenable_if或类似的,结合 eg is_function

于 2009-10-29T02:47:02.077 回答
0

在符合标准的 C++ 实现中,这些多个模棱两可的模板应该会产生错误(歧义是由签名定义的,而不是由正文定义的)。我不知道有任何 C++ 编译器违反了允许此代码的标准(这并不意味着没有任何足够疯狂的编译器,只是我没有听说过任何这样的编译器;-)。

于 2009-10-29T02:36:22.043 回答
0

这不能按照您指定的方式直接实现,但有一种解决方法。可以定义一个模板转换操作符,它的类型参数可以从预期的目标类型推导出来。因此,您可以引入代理类:

class read_proxy
{
public:
    read_proxy(std::istream& in) : in(in) {}
    template<class T> operator T () { T x; in >> x; return x; }
private:
    std::istream& in;
};

read_proxy read(std::istream& in)
{
    return read_proxy(in);
}

然后按照您最初的要求使用它:

void foo(float) {}

int main()
{
    int x = read(std::cin);
    foo(read(std::cin)); // float
}

这里的潜在问题是,如果有人试图持久化返回的代理本身,他可能会遇到生命周期问题(因为它包含对流的简单引用,而后者可能会在代理之前被破坏)。

于 2009-10-29T02:47:57.037 回答
0

正如其他答案表明它不符合标准。

您没有显示预期的用法,因此很难弄清楚您到底在追求什么,但您可以自己实现代码(见下文),可以使用 SFINAE 进行更多改进,以避免为每个特定类创建转换模板:

#include <iostream>
#include <sstream>

using namespace std;

struct A
{
    int x;
    A() : x(0) {}
};

istream& operator>>(istream& in, A& a)
{
    in >> a.x;
    return in;
}

ostream& operator<<(ostream& on, A& a) { return on << "A: " << a.x; }

struct B
{
    int x;
    B(istream& in) : x(0) { in >> x; }
};

ostream& operator<<(ostream& on, B& b) { return on << "B: " << b.x; }

struct C
{
    int x;
    C() : x(0) {}

    static C OfStreamX(istream& in)
    {
        C c;
        in >> c.x;
        return c;
    }
};

ostream& operator<<(ostream& on, C& c) { return on << "C: " << c.x; }

template <typename T> T Read(istream& in);
template <> A Read(istream& in)
{
    A a;
    in >> a;
    return a;
}

template <> B Read(istream& in) { return B(in); }
template <> C Read(istream& in) { return C::OfStreamX(in); }

int main()
{
    string data("23 45 67");
    istringstream in(data);

    A a = Read<A>(in);
    cout << a << endl;

    B b = Read<B>(in);
    cout << b << endl;

    C c = Read<C>(in);
    cout << c << endl;
}

输出:

A: 23
B: 45
C: 67
于 2009-10-29T03:21:59.270 回答