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

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

Когда я повторяю это с одним аргументом шаблона, также по умолчанию, специализация, похоже, все еще хорошо сформирована, явно предоставляя типчто по умолчанию в базовом шаблоне.Однако в этом случае кажется, что это игнорируется и не считается более специализированным.Базовая версия всегда выбирается.

Может кто-нибудь объяснить, почему это происходит?

#include <iostream>
#include <utility>
#include <type_traits>

struct F1 { int operator()(); };
struct F2 {};

template<typename T, typename = int> struct A { constexpr static bool function_call_operator{false}; };
template<typename T> struct A<T, decltype(std::declval<T>()())> { constexpr static bool function_call_operator{true}; };

template<typename T = int> struct B { constexpr static bool function_call_operator{false}; };
template<typename T> struct B<decltype(std::declval<T>()())> { constexpr static bool function_call_operator{true}; };

void f0() {}

int main() {
    std::cout << std::boolalpha;
    std::cout << A<F1>::function_call_operator << std::endl; // true; OK
    std::cout << A<F2>::function_call_operator << std::endl; // false; OK

    std::cout << B<F1>::function_call_operator << std::endl; // false; why ?
    std::cout << B<F2>::function_call_operator << std::endl; // false; OK
    std::cout << std::noboolalpha;
}

Вот онлайн скомпилированная версия с компилятором C ++ 14.

1 Ответ

2 голосов
/ 10 июня 2019

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

Поскольку специализация для B предназначена для int (в случаях F1 и F2)

template <typename T>
struct B<decltype(std::declval<T>()())> // decltype(...) is int, in F1 and F2 cases
 { constexpr static bool function_call_operator{true}; };

Вы создаете экземпляр B с F1 и F2. Оба они отличаются от int.

Только универсальная версия соответствует B<F1> и B<F2>.

Специализация B никогда не выбирается, потому что T не вычитается (из B<int> вы не можете вывести F1 или F2).

...