#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 <----
В соответствии с логикой следующим должен быть результат для вышеуказанных тестов:
Resove<B1>::type = MyClass
Resove<B2>::type = MyClass
Resove<D1>::type = D1
Resove<D2>::type = MyClass
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 sD3
. 1-й проходитB1
, а 2-й проходитB2
. Почему оба отбрасываются. Вы можете просто попробовать удалить любой изtypedef
s, и тогдаResove<D3>::type = MyClass
будет результат.5. @iammilind: Существует двусмысленность, эта двусмысленность приводит к тому, что эта конкретная замена приводит к сбою, и именно тогда запускается SFINAE и предотвращает эту ошибку, отбрасывая вашу специализацию из жизнеспособных кандидатов. В результате у вас остается только один кандидат, который обеспечивает жизнеспособную замену — по умолчанию — и является выбранным.