Suppose I'm writing a template function foo that has type parameter T. It gets an object of type T that must have method bar(). And inside foo I want to create a vector of objects of type returned by bar.
In GNU C++ I can write something like that:
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;
}
How to do the same thing in Microsoft Visual C++? Is there some way to write this code that works in both GNU C++ and Visual C++?
You can do that in standard 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);
}
See Conditional Love for an explanation.
C++0x provides the decltype
keyword as part of the standard, which solves your problem like so:
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 also supports this, as do GCC 4.3+ and Comeau 4.3.9+ (thanks Patrick).
If you're requiring the type used in your template to have the "bar" function, you can also require it to have a typedef for the type returned from bar. That's the way the standard library usually handles this type of issue (every container has a value_type typedef, for example).
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);
You could try Boost.Typeof, which claims to support VC 8.
#include <boost/typeof/typeof.hpp>
template<typename T>
void foo(T x) {
std::vector<BOOST_TYPEOF(x.bar())> v;
...
If you defer the work to another template function, you can use template argument deduction on T::bar to figure it out.
// 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);
}
However, if you need the type in several places, it is probably better to use the techniques in one of the other answers.
If you're using Visual C++ 10, they support the "decltype" operator, which will return the type of the given expression.