Аргумент шаблона вычета C ++ - PullRequest
6 голосов
/ 14 декабря 2011

Пожалуйста, рассмотрите код ниже:

template<typename T>
bool function1(T some_var) { return true; }

template <typename T>
bool (*function2())(T) {
  return function1<T>;
}

void function3( bool(*input_function)(char) ) {}

Если я позвоню

function3(function2<char>());

, все в порядке.Но если я позвоню

function3(function2());

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

Не могли бы вы, пожалуйста, посоветовать (дать представление), как переписать функциюи / или function2 (может быть, фундаментально переписать с использованием классов), чтобы все было в порядке?

* Добавлено *

Я пытаюсь сделать что-то простое, например лямбда-выраженияв Boost.LambdaLib (может быть, я на неправильном пути):

sort(some_vector.begin(), some_vector.end(), _1 < _2)

Я сделал это:

template<typename T>
bool my_func_greater (const T& a, const T& b) {
  return a > b;
}

template<typename T>
bool my_func_lesser (const T& a, const T& b) {
  return b > a;
}

class my_comparing {
 public:
  int value;
  my_comparing(int value) : value(value) {}
  template <typename T>
  bool (*operator<(const my_comparing& another) const)(const T&, const T&) {
    if (this->value == 1 && another.value == 2) {
      return my_func_greater<T>;
    } else {
      return my_func_greater<T>;
    }
  }
};

const my_comparing& m_1 = my_comparing(1);
const my_comparing& m_2 = my_comparing(2);

Работает:

sort(a, a + 5, m_1.operator< <int>(m_2));

Но я хочу, чтобы он не требовал аргумента шаблона, как в LambdaLib.

Ответы [ 4 ]

5 голосов
/ 14 декабря 2011

Удержание из типа возврата невозможно. Так что function2 не может быть выведено из ожидаемого типа возврата.

Однако можно вывести оператор приведения. Таким образом, вы можете заменить function2 вспомогательной структурой, такой как: К сожалению, нет стандартного синтаксиса для объявления оператора приведения к указателю на функцию без typedef, и вывод типа не будет работать через typedef. Следующее определение работает в некоторых компиляторах (работает в G ++ 4.5, не работает в VC ++ 9):

struct function2 {
    template <typename T>
    (*operator bool())(T) {
        return function1<T>;
    }
};

(см. Также Оператор преобразования C ++ для преобразования в указатель функции ).

Звонок должен выглядеть так же.

Примечание: C ++ 11 вводит альтернативный синтаксис typedef, который может быть шаблонным. Это было бы как:

struct function2 {
    template <typename T>
    using ftype = bool(*)(T);

    template <typename T>
    operator ftype<T>() {
        return function1<T>;
    }
};

но у меня нет ни G ++ 4.7, ни VC ++ 10, поэтому я не могу проверить, работает ли он на самом деле.


Объявление добавлено:

Хитрость в Boost.Lambda заключается в том, что он не возвращает функции, а функторы. И функторы могут быть шаблонами классов. Итак, у вас будет:

template<typename T>
bool function1(T some_var) { return true; }

class function2 {
    template <typename T>
    bool operator()(T t) {
        function1<T>;
    }
};

template <typename F>
void function3( F input_function ) { ... input_function(something) ... }

Теперь вы можете написать:

function3(function2);

и он будет разрешать шаблон внутри function3. Все STL принимают функторы в качестве шаблонов, так что это будет работать со всеми STL.

Однако, если вы не хотите использовать function3 в качестве шаблона, есть способ. В отличие от указателя на функцию, шаблон std::function (только C ++ 11, используйте boost::function для более старых компиляторов) может быть создан из любого функтора (который включает простые указатели на функции). Итак, учитывая вышесказанное, вы можете написать:

void function3(std::function<bool ()(char)> input_function) { ... input_function(something) ... }

и теперь вы можете звонить:

function3(function2());

Дело в том, что std::function имеет конструктор шаблонов, который внутренне генерирует оболочку шаблона и сохраняет указатель на его метод, который можно вызывать без дополнительных шаблонов.

5 голосов
/ 14 декабря 2011

Компилятор не использует контекст выражения для вывода параметров своего шаблона.Для компилятора function3(function2()); выглядит как

auto tmp = function2();
function3(tmp);

И он не знает, что такое function2 параметр шаблона.

2 голосов
/ 14 декабря 2011

После вашего редактирования, я думаю, что вы хотите сделать, можно сделать проще. Смотрите следующий тип:

struct Cmp {
  bool const reverse;
  Cmp(bool reverse) : reverse(reverse) {}
  template <typename T> bool operator()(T a, T b) {
    return reverse != (a < b);
  }
};

Теперь в вашем operator< вы возвращаете нетипизированный Cmp экземпляр в зависимости от порядка ваших аргументов, то есть m_2 < m_1 вернет Cmp(true), а m_1 < m_2 вернет Cmp(false) .

Поскольку существует шаблон operator(), компилятор выведет нужную функцию внутри sort, а не при вашем вызове sort.

1 голос
/ 15 декабря 2011

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

Шаблон не может определить его тип, потому что компилятор не знает, какой тип вы ожидаете вернуть. Ниже приведен простой пример, который похож на вашу функцию2 ().

template<typename T>
T foo() {
    T t;
    return t;
};

вызвать эту функцию

foo(); // no type specified. T cannot be deduced.

Можно ли переместить объявление шаблона на уровень класса следующим образом:

template<typename T>
bool my_func_greater (const T& a, const T& b) {
  return a > b;
}

template<typename T>
bool my_func_lesser (const T& a, const T& b) {
  return b > a;
}

template <typename T>
class my_comparing {
public:
    int value;
    my_comparing(int value) : value(value) {}
    bool (*operator<(const my_comparing& another) const)(const T&, const T&) {
        if (this->value == 1 && another.value == 2) {
            return my_func_greater<T>;
        } else {
            return my_func_greater<T>;
        }
    }
};

и объявите m_1 и m_2, как показано ниже:

const my_comparing<int>& m_1 = my_comparing<int>(1);
const my_comparing<int>& m_2 = my_comparing<int>(2);

Теперь вы можете сравнить следующим образом:

if( m_1 < m_2 )
    cout << "m_1 is less than m_2" << endl;
else
    cout << "m_1 is greater than m_2" << endl;

Я знаю, что это просто, и все это знают. Поскольку никто не опубликовал это, я хочу попробовать.

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