2010-05-22 28 views
4

假设我正在编写一个具有类型参数T的模板函数foo。它获取了一个必须具有方法bar()的类型为T的对象。并且在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++中都可用的代码吗?

回答

13

你可以做,在标准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

+1

现在,这只是错误的。是的,我知道;这是正确的”。但它仍然是错误的。我想我需要躺下一分钟。 – 2010-05-22 13:11:24

+0

@Marcelo,有条件的爱情在其他场合也证明是有用的。看到[这一个](http://stackoverflow.com/questions/1353757/how-do-i-refer-to-stdsinconst-valarraydouble) – 2010-05-22 13:26:17

+1

我的头痛以某种好方式...这是一个幽灵般的东西好吧!如果我没有记错,C++ 0x是不是应该为我们提供一个好东西? – 2010-05-22 14:08:01

4

如果您要求模板中使用的类型具有“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); 
+5

你应该使用'typename T :: bar_type'来使代码符合标准。 – 2010-05-22 13:57:15

+0

谢谢!我将使用这个解决方案。我是新来的泛型编程,并没有考虑typedef-s。 – rem 2010-05-22 15:26:38

1

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

#include <boost/typeof/typeof.hpp> 

template<typename T> 
void foo(T x) { 
    std::vector<BOOST_TYPEOF(x.bar())> v; 
    ... 
+0

谢谢!但我不想在其他库上创建依赖关系。 – rem 2010-05-22 15:40:47

0

如果你使用Visual C++ 10,他们支持 “decltype” 操作符,将返回的类型给出的表达。

+1

对于支持C++ 0x功能的任何C++编译器都是如此decltype; GCC 4.3或更高版本也支持这一点。 – 2010-05-22 14:00:59

1

如果您将工作推迟到另一个模板函数,您可以在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); 
} 

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

+0

谢谢!是的,我需要在多个地方使用该类型。 – rem 2010-05-22 15:41:33

7

的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或更高版本和科莫4.3.9+ (感谢帕特里克)。

+0

GCC 4.3+和Comeau 4.3.9+ – 2010-05-22 14:18:19

+0

谢谢!我需要研究新的C++ 0x功能:)但我需要代码来编译旧版本。顺便说一句,我收到编译错误,试图在gcc-3.4.3中编译它:http://ideone.com/3jWob – rem 2010-05-22 15:31:06

+2

如果bar可能返回一个引用,你必须使用'typename remove_reference :: type' – sellibitze 2010-05-22 17:10:06