Тип не наследуется в SFINAE для множественного наследования?

#c #templates #multiple-inheritance #type-inference #sfinae

#c #шаблоны #множественное наследование #вывод типа #sfinae

Вопрос:

Я использую механизм SFINAE для определения типа. Resolve<T>::type выводится T , если class T не содержит yes , и выводится MyClass , если содержит yes .

 class MyClass {};

template<typename>
struct void_ { typedef void check; };

template<typename T, typename = void>
struct Resolve { typedef T type; };

template<typename T>
struct Resolve <T, typename void_<typename T::yes>::check> {
    typedef MyClass type;
};
  

Теперь у меня есть простые тестовые классы как,

 struct B1 { typedef int yes; }; // 1
struct B2 { typedef int yes; }; // 2
struct D1 {};  // 3
struct D2 : B1 {};  // 4
struct D3 : B1, B2 {}; // 5 <----
  

В соответствии с логикой следующим должен быть результат для вышеуказанных тестов:

  1. Resove<B1>::type = MyClass
  2. Resove<B2>::type = MyClass
  3. Resove<D1>::type = D1
  4. Resove<D2>::type = MyClass
  5. Resove<D3>::type = MyClass или ошибка компилятора (из-за неоднозначности между B1, B2)

Как ни странно, в тестовом примере (5) этого не происходит. Результат,

 Resolve<D3>::type = D3;
  

Кто-нибудь может объяснить, какая магия происходит специально для множественного наследования? Отсутствие ошибки компилятора является стандартным поведением? Вот демонстрация.

Ответ №1:

Почему вы ожидаете ошибки компилятора? Вы знаете, что SFINAE означает Substitution Failure Is Not An Error «правильно»?

При замене T на D3 выражение становится неоднозначным. Из-за SFINAE этот сбой не считается ошибкой, и ваша специализация просто удаляется как кандидат. Все дело в том, чтобы НЕ получить ошибку компилятора.

Комментарии:

1. Правильно. Но в этом случае есть 2 typedef s, которые поступают в D3 , через B1 и B2 ; вот почему я ожидал ошибки. Если не ошибка, то type должно быть Myclass как в случае D2 .

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

3. @Bjorn: Как это не связано? В случае OP ошибки нет, потому что специализация приводит к сбою, а шаблон по умолчанию является подходящей заменой и является единственным в наборе, поэтому двусмысленности нет.

4. В чем моя путаница, почему не должно быть никакой двусмысленности? В нем typedef участвуют 2 s D3 . 1-й проходит B1 , а 2-й проходит B2 . Почему оба отбрасываются. Вы можете просто попробовать удалить любой из typedef s, и тогда Resove<D3>::type = MyClass будет результат.

5. @iammilind: Существует двусмысленность, эта двусмысленность приводит к тому, что эта конкретная замена приводит к сбою, и именно тогда запускается SFINAE и предотвращает эту ошибку, отбрасывая вашу специализацию из жизнеспособных кандидатов. В результате у вас остается только один кандидат, который обеспечивает жизнеспособную замену — по умолчанию — и является выбранным.