【问题标题】:Declare variables that depend on unknown type in template functions在模板函数中声明依赖于未知类型的变量
【发布时间】:2010-05-22 12:52:49
【问题描述】:

假设我正在编写一个具有类型参数 T 的模板函数 foo。它获取一个类型为 T 的对象,该对象必须具有方法 bar()。在 foo 内部,我想创建一个由 bar 返回的类型的对象向量。

在 GNU C++ 中我可以写这样的东西:

template<typename T>
void foo(T x) {
    std::vector<__typeof(x.bar())> v;
    v.push_back(x.bar());
    v.push_back(x.bar());
    v.push_back(x.bar());
    std::cout << v.size() << std::endl;
}

如何在 Microsoft Visual C++ 中做同样的事情?有没有办法编写在 GNU C++ 和 Visual C++ 中都可以使用的代码?

【问题讨论】:

    标签: c++ visual-c++ templates typeof


    【解决方案1】:

    您可以在标准 c++ 中做到这一点

    template<typename T>
    struct id { typedef T type; };
    
    template<typename T>
    id<T> make_id(T) { return id<T>(); }
    
    struct any_type {
      template<typename T>
      operator id<T>() const { return id<T>(); }
    };
    
    template<typename T, typename U>
    void doit(id<T>, U& x) {
      std::vector<T> v;
      v.push_back(x.bar());
      v.push_back(x.bar());
      v.push_back(x.bar());
      std::cout << v.size() << std::endl;
    }
    
    template<typename T>
    void foo(T x) {
        doit(true ? any_type() : make_id(x.bar()), x);
    }
    

    请参阅Conditional Love 了解说明。

    【讨论】:

    • 现在,这是错误的。是的,我知道;这是正确的”。但这仍然是错误的。我想我需要躺一会。
    • @Marcelo,有条件的爱在其他场合也被证明是有用的。见this one
    • 我的头好痛……这真是一件令人毛骨悚然的事情,好吧!如果我没记错的话,C++0x 不应该在这里给我们带来好处吗?
    • @Matthieu,另一个人提到了decltype。我认为这是获取 x.bar() 类型返回的 C++0x 方式。
    • 谢谢!这也很好,虽然看起来很吓人。但是 typedef-s 对我来说已经足够了。
    【解决方案2】:

    C++0x 提供了 decltype 关键字作为标准的一部分,这样可以解决您的问题:

    template<typename T>
    void foo(T x) {
        std::vector<decltype(x.bar())> v;
        v.push_back(x.bar());
        v.push_back(x.bar());
        v.push_back(x.bar());
        std::cout << v.size() << std::endl;
    }
    

    Visual Studio 2010 也支持这一点,GCC 4.3+ 和 Comeau 4.3.9+ 也是如此(感谢 Patrick)。

    【讨论】:

    • GCC 4.3+ 和 Comeau 4.3.9+ 也是如此
    • 谢谢!总有一天我需要研究新的 C++0x 特性 :) 但我也需要在旧版本中编译代码。顺便说一句,我在尝试在 gcc-3.4.3 中编译它时遇到编译错误:ideone.com/3jWob
    • 如果 bar 可能返回一个引用,你必须使用 typename remove_reference&lt;decltype(x.bar())&gt;::type
    【解决方案3】:

    如果您要求模板中使用的类型具有“bar”函数,您还可以要求它具有从 bar 返回的类型的 typedef。这就是标准库通常处理此类问题的方式(例如,每个容器都有一个 value_type typedef)。

    class Bar1 {
    public:
        typedef int bar_type;
    
        bar_type bar();
        ...
    };
    
    template<typename T>
    void foo(T x) {
        std::vector<T::bar_type> v;
        v.push_back(x.bar());
        v.push_back(x.bar());
        v.push_back(x.bar());
        std::cout << v.size() << std::endl;
    }
    
    Bar1 b;
    foo(b);
    

    【讨论】:

    • 您应该使用typename T::bar_type 使代码符合标准。
    • 谢谢!我会使用这个解决方案。我是泛型编程的新手,没有考虑过 typedef-s。
    【解决方案4】:

    你可以试试Boost.Typeof,它声称支持 VC 8。

    #include <boost/typeof/typeof.hpp>
    
    template<typename T>
    void foo(T x) {
        std::vector<BOOST_TYPEOF(x.bar())> v;
        ...
    

    【讨论】:

    • 谢谢!但我不希望在其他库上创建依赖项。
    【解决方案5】:

    如果你将工作推迟到另一个模板函数,你可以使用 T::bar 上的模板参数推导来解决。

    // templated on the original type, and the return type of the function
    template <typename T, typename mem_fn_return_type>
    void doThePush (T& instance, mem_fn_return_type (T::*barptr)(void))
    {
      std::vector<mem_fn_return_type> v;
      v.push_back((instance.*barptr)());
      v.push_back((instance.*barptr)());
      v.push_back((instance.*barptr)());
      std::cout << v.size() << std::endl;
    }
    
    template <typename T>
    void foo(T x)
    {
      doThePush(x, &T::bar);
    }
    

    但是,如果您需要在多个地方使用该类型,则最好在其他答案之一中使用这些技术。

    【讨论】:

    • 谢谢!是的,我需要在多个地方使用该类型。
    【解决方案6】:

    如果您使用的是 Visual C++ 10,它们支持“decltype”运算符,它将返回给定表达式的类型。

    【讨论】:

    • 这适用于任何支持 C++0x 特性 decltype 的 C++ 编译器; GCC 4.3 或更新版本也支持这一点。
    猜你喜欢
    • 1970-01-01
    • 2013-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多