Почему не удается создать экземпляр шаблона класса для неиспользуемой функции-члена - PullRequest
5 голосов
/ 10 октября 2019

Что не так с этим:

#include <type_traits>

struct A;

template<typename T>
struct B
{
    template<typename=std::enable_if<std::is_copy_constructible<T>::value>>
    void f1() {}
};

template<typename T>
struct C {};


// Type your code here, or load an example.
int main() {
    // Following fails
    B<A> b;
    // Could use this:
    // b.f1<C>();

    // This complies
    C<A> c;

    return 0;
}

/* This to be in or not doesn't make a difference
struct A
{};
*/

Я пробовал это здесь: https://godbolt.org/z/NkL44s с различными компиляторами:

  • x86-64 gcc 9.2: компилирует
  • x86-64 gcc (транк): сбой
  • x86-64 clang 6.0.0: компилируется
  • x86-64 clang 7.0.0 и более поздних версий: сбой
  • x64 msvc v19.22: компилируется
  • x64 msvc v19.23 (внутреннее тестирование): сбой

Так почему более поздние компиляторы отклоняют это? При создании экземпляра B<A> неясно, в какой форме будет использоваться f1 или будет ли он использоваться вообще. Так почему компилятор жалуется на это? Не следует ли проверять функцию шаблона элемента f1, только если она действительно используется?


Редактировать :
Как упоминалось в комментариях, я допустил непреднамеренную ошибку вкод выше: std::enable_if должен был быть std::enable_if_t, как на этой исправленной площадке: https://godbolt.org/z/cyuB3d

Это меняет картину компиляторов, передающих этот код без ошибок:

  • gcc: сбой
  • лязг: сбой
  • x64 msvc v19.22: компилируется
  • x64 msvc v19.23 (внутреннее тестирование): сбой

Однако остается вопрос: почему параметр шаблона по умолчанию для функции, которая никогда не используется, приводит к сбою компиляции?

Ответы [ 2 ]

3 голосов
/ 10 октября 2019

Причина в том, что std::is_constructible требуется полный тип: ( Таблица 42 )

Шаблон

template <class T>
struct is_­copy_­constructible;

Предварительные условия

T должен быть полным типом, cv void или массивом с неизвестной границей.

Невыполнение требования библиотеки "must" приводит к неопределенному поведению.

2 голосов
/ 10 октября 2019

С cppreference на is_copy_constructible<T>:

T должно быть полным типом (возможно, cv-квалифицированным) void или массивом неизвестной границы. В противном случае поведение не определено.

Так что, похоже, у вас просто обычный UB в более старых версиях компилятора, а более новые достаточно хороши, чтобы сказать вам, что A должен быть полным типом.

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

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