Почему компилятор не может определить типы возвращаемых данных? - PullRequest
3 голосов
/ 22 марта 2019

Может ли компилятор не определить тип возвращаемого значения функции, если тип возвращаемого значения является параметром шаблона?Или я делаю ошибку в следующем коде.

#include <iostream>

template <typename TT>                                                                                                                                                                                                                                                                                                                                                                        
TT retBoolFail(bool a) {                                                                                                                                                                                                                                                                                                                                                                      
    return true;                                                                                                                                                                                                                                                                                                                                                                              
}

template <typename TT>                                                                                                                                                                                                                                                                                                                                                                        
void retBoolSuccess(bool a, TT& ret) {                                                                                                                                                                                                                                                                                                                                                        
    ret = true;                                                                                                                                                                                                                                                                                                                                                                               
    return;                                                                                                                                                                                                                                                                                                                                                                                   
}

int main() {                                                                                                                                                                                                                                                                                                                                                                                  
    bool ret;                                                                                                                                                                                                                                                                                                                                                                                 
    retBoolSuccess(true, ret);  // Success                                                                                                                                                                                                                                                                                                                                                    
    retBoolFail(true);          // Failure                                                                                                                                                                                                                                                                                                                                                    
    return 0;                                                                                                                                                                                                                                                                                                                                                                                 
}

строка 'RetBoolFail (true)' завершается ошибкой со следующей ошибкой.

-*- mode: compilation; default-directory: "~/work/c++/tupleTemplate/" -*-
Compilation started at Thu Mar 21 16:52:50

g++ -c simpletemp.cc  -std=c++1z -g; g++ -o simpletemp simpletemp.o
simpletemp.cc: In function ‘int main()’:
simpletemp.cc:17:21: error: no matching function for call to ‘retBoolFail(bool)’
     retBoolFail(true);          // Failure
                     ^
simpletemp.cc:4:4: note: candidate: template<class TT> TT retBoolFail(bool)
 TT retBoolFail(bool a) {
    ^
simpletemp.cc:4:4: note:   template argument deduction/substitution failed:
simpletemp.cc:17:21: note:   couldn't deduce template parameter ‘TT’
     retBoolFail(true);          // Failure
                     ^
Compilation finished at Thu Mar 21 16:52:50

Спасибо.

Ответы [ 3 ]

3 голосов
/ 22 марта 2019

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

1 голос
/ 22 марта 2019

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

Одна из причин, по которой это правило будет трудно изменить в Стандарте, заключается в том, как все работает, если имя перегружено. Более полная картина есть:

  1. Поиск имени находит набор функций и шаблонов функций.

  2. Для каждого шаблона функции в наборе аргументы шаблона определяются из явных аргументов шаблона, дедукции и / или аргументов шаблона по умолчанию. Если вычет не удался или если замена определенных аргументов шаблона в тип функции делает что-то недопустимое, шаблон функции просто отбрасывается из набора перегрузки как нежизнеспособный.

  3. Для каждой сигнатуры функции (будь то из шаблона или нет) выполняется проверка на соответствие параметров функции и аргументов функции. Если нет, функция является нежизнеспособной и отбрасывается из набора перегрузки.

  4. Разрешение перегрузки сравнивает остальные жизнеспособные функции. Для большей части процесса типы функций из шаблонов обрабатываются так же, как не шаблонные функции, но есть несколько окончательных правил разрыва связей, специфичных для специализаций шаблонов функций.

  5. Если разрешение перегрузки выбрало специализацию шаблона функции, и контекст является тем, для которого требуется определение функции, то для создания этого определения также создается тело функции. Если подстановка параметров аргументов шаблона в тело функции делает что-то недопустимое, программа некорректна.

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

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

Если указатель на функцию или ссылка на функцию инициализируется из имени шаблона функции (или его адреса для регистра указателя), возвращаемые типы участвуют в выводе аргумента шаблона:

template <typename TT>
TT f();

unsigned int (&func_ptr)() = f; // TT deduced as unsigned int

int g(double (*)());
int g_of_f = g(f);  // TT deduced as double

Класс или шаблон класса могут иметь шаблон функции преобразования. Тогда некоторые использования выражения с этим типом класса могут неявно использовать этот шаблон, что требует вывода аргументов шаблона в его возвращаемом типе (который также следует за ключевым словом operator в его объявлениях).

class A {
public:
    template <typename TT>
    operator std::shared_ptr<TT>() const;
};

std::shared_ptr<int> p = A{}; // TT deduced as int

Также обратите внимание, что функция или шаблон функции, использующий «тип заполнителя» в качестве своего возвращаемого типа (возвращаемый тип содержит ключевое слово auto), действительно выводит свой возвращаемый тип из операторов return тела (которые не пропускаются, потому что "if constexpr"). Хотя функция без заголовка шаблона - это всего лишь одна функция с одним конкретным типом, а не шаблон функции, и этот вывод является отдельным шагом от любых выводов аргументов шаблона.

auto retBool(bool a) {
    return true;       // return type is bool
}

template <typename T>
constexpr const auto* constify(T* ptr) {
    return ptr;       // return type is const T* (T* if T is already const)
}
1 голос
/ 22 марта 2019

Вывод типа не работает для возвращаемых типов только для аргументов шаблона функции.

В вашем случае вы должны использовать

retBoolFail<bool>(true);

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

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