Объявите переменные, которые зависят от неизвестного типа в шаблонных функциях - PullRequest
4 голосов
/ 22 мая 2010

Предположим, я пишу шаблонную функцию foo с параметром типа T. Он получает объект типа 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 ++?

Ответы [ 6 ]

13 голосов
/ 22 мая 2010

Вы можете сделать это в стандартном 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);
}

См. Условная Любовь для объяснения.

7 голосов
/ 22 мая 2010

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+ (спасибо, Патрик).

4 голосов
/ 22 мая 2010

Если вам требуется, чтобы тип, используемый в вашем шаблоне, имел функцию "bar", вы также можете потребовать, чтобы он имел typedef для типа, возвращаемого из bar. Именно так стандартная библиотека обычно обрабатывает проблему такого типа (например, у каждого контейнера есть 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);
1 голос
/ 22 мая 2010

Если вы отложите работу до другой функции шаблона, вы можете использовать вывод аргумента шаблона на 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);
}

Однако, если вам нужен тип в нескольких местах, вероятно, лучше использовать приемы в одном из других ответов.

1 голос
/ 22 мая 2010

Вы можете попробовать Boost.Typeof , который утверждает, что поддерживает VC 8.

#include <boost/typeof/typeof.hpp>

template<typename T>
void foo(T x) {
    std::vector<BOOST_TYPEOF(x.bar())> v;
    ...
0 голосов
/ 22 мая 2010

Если вы используете Visual C ++ 10, они поддерживают оператор "decltype", который будет возвращать тип данного выражения.

...