Почему C ++ не может определить тип шаблона? - PullRequest
2 голосов
/ 25 августа 2011

Почему компилятор не может определить эти параметры шаблона? Есть ли способ заставить это сделать?

(я использую Visual Studio 2010.)

template<typename T, typename TFunc>
void call(TFunc func) { func(T()); }

void myfunc(void *) { }

int main() { call(myfunc); }

Ответы [ 3 ]

11 голосов
/ 25 августа 2011

T нигде не отображается в списке параметров, поэтому T не может быть выведено из аргументов функции. Все типы, которые должны быть выведены, должны появляться в выведенных контекстах в списке параметров. Например,

template <typename TReturn, typename TParameter>
void call(TReturn (*f)(TParameter))
{
    f(TParameter());
}
3 голосов
/ 25 августа 2011

Вывод параметра шаблона для шаблонов функций работает только на основе аргументов функций, ничего больше. Определение функции никогда не рассматривается с целью определения параметров шаблона, поэтому ваш параметр T не может быть выведен.

Вы можете исправить ситуацию, включив тип в сигнатуру функции: поскольку вы ожидаете, что внешняя функция будет вызываться с самой функцией, сделайте это явным:

template <typename T> void foo(void(*f)(T))
{
  T x;
  f(x);
  // ...
}
2 голосов
/ 25 августа 2011

Объедините перегрузку функций с функторами, и в общем случае становится невозможно определить, какие аргументы можно передать вызываемой сущности.

Рассмотрим, например,

struct FunctorExample {
    void operator()(int x) {...}
    std::string operator()(const std::string& ) {...}
};

Если бы был какой-то способ уговорить компилятор сопоставить шаблон с аргументами, он должен был бы иметь неопределенное или ошибочное поведение при применении к FunctorExample.

Вместо этого, как представляется, тенденция заключается в том, что когда вы хотите шаблонизировать метапрограмму с помощью функторов, вы указываете функтор и список аргументов. Примеры (от макушки головы): boost::result_of и boost::fusion.

Редактировать : Тем не менее, если вы хотите несколько ограничить свое внимание и можете использовать некоторый синтаксис C ++ 11 (decltype), вы можете устроить для интроспекции немного больше:

// Support functors with a very simple operator():
template <typename T> struct argument :
    public argument<decltype(&T::operator())> {};

// Pointers to member functions
template <typename C, typename R, typename A> struct argument<R(C::*)(A)>
    {typedef A type;};

// Function types
template <typename R, typename A> struct argument<R(A)> {typedef A type;};

// Function pointer types.
template <typename R, typename A> struct argument<R(*)(A)> {typedef A type;};

// Now for call:
template <typename FuncType>
void call(FuncType func) { 
    typedef typename argument<FuncType>::type Arg;
    func(Arg());
}

// example:
class FunctorInt {public: int operator()(int ) {return 0;};};
void myfunc(void *) {}

int main() {
    call(myfunc);
    call(FunctorInt());
}

Шаблоны Variadic могут использоваться для расширения этого материала для поддержки более чем одного аргумента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...