Различия компилятора при использовании std :: enable_if в типе возвращаемого значения шаблонной функции-члена - PullRequest
0 голосов
/ 23 сентября 2018

Я попытался определить две «перегрузки» для метода в struct Node, который в зависимости от параметра шаблона структуры вызывает различные варианты поведения.

Мне известно, что я мог бы использовать другие методы (например, if constexprили что-то еще) ..

Меня беспокоит то, что я «обманул» экспериментальную версию gcc 9.0.0 20180919 для компиляции этого, но все другие недавние компиляторы, доступные в wandbox (permlink ниже), этого не делают.Я полагаю, что gcc8 и clang6 / 7 делают правильные вещи здесь?

Спасибо за вашу помощь!

#include <iostream>
#include <type_traits>

enum laziness { lazy, nonlazy };
enum logic { AND, OR };

template<laziness LA, logic LO>
struct Node{
    template<typename = void>
    std::enable_if_t<LA==lazy> printLaziness () const {
      std::cout << "lazy" << std::endl;
    }
    template<typename = void>
    std::enable_if_t<LA==nonlazy> printLaziness () const {
      std::cout << "non-lazy" << std::endl;
    }
};


int main () {
    Node<lazy, AND> x{};
    x.printLaziness();
    Node<nonlazy, OR> y{};
    y.printLaziness();
}

https://wandbox.org/permlink/d2IaWwt9GJn31Wmq

1 Ответ

0 голосов
/ 24 сентября 2018

Код неверно сформирован, и этот экспериментальный gcc 9.0.0 неверен, чтобы его игнорировать.

Главное, что нужно понять о правиле SFINAE, это то, что оно применяется при формировании недопустимого типа или выраженияпри подстановке параметра шаблона функции в аргументы шаблона по умолчанию для других параметров шаблона функции или в тип функции, как описано во введении в разделе [temp.deduct] ;или при определении, соответствует ли частичная специализация шаблона класса или какая частичная специализация является наиболее специализированной.Но в вашем коде недопустимый тип формируется при замене параметра LA шаблона класса, а не параметра шаблонов функций.

Также актуален параграф [temp.inst] / 2:

Неявное создание экземпляра специализации шаблона класса вызывает

  • неявное создание объявления, но не определений не-удаленные функции-члены класса, классы-члены, перечисления членов-областей, статические члены-данные, шаблоны членов и друзья;и

  • неявная реализация определений удаленных функций-членов, перечисления членов с незаданной областью и анонимные объединения-члены.

неявная реализацияСпециализация шаблона класса не приводит к неявной реализации аргументов по умолчанию или noexcept-спецификатора s функций-членов класса.

Поскольку определения x и y в пределахmain требует, чтобы типы Node<lazy, AND> и Node<nonlazy, OR> были завершены, шаблон класса должен быть создан для этих двух специализаций.И создание шаблона класса означает создание объявлений шаблона функции, поэтому в каждом случае программа плохо сформирована, поскольку это объявление содержит независимый недопустимый тип.


Примечание: как вы упомянули, if constexpr, пожалуй, самый простой способ решить эту проблему в C ++ 17.(Публичная функция может просто вызывать одну из двух закрытых функций с разными именами, если вы хотите, чтобы реализации были отдельными.) Но в C ++ 20 будут введены «ограничения» для шаблонов и функций, которые обеспечат еще более приятное решение:

template<laziness LA, logic LO>
struct Node{
    void printLaziness () const requires (LA==lazy) {
      std::cout << "lazy" << std::endl;
    }
    void printLaziness () const requires (LA==nonlazy) {
      std::cout << "non-lazy" << std::endl;
    }
};

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

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