Согласно [temp.deduct.conv]:
Шаблон вывод аргумента делается путем сравнения тип возвращаемого шаблона функции преобразования (назовем его P) с типом, который необходим в результате (назовите это A, см. 8.5, 13.3.1.5 и 13.3.1.6 для определения этого типа), как описано в 14.8.2.5.
В простом случае:
template <class Q>
operator CFoo<Q>& const;
Это просто, мы пытаемся вывести CFoo<Q>&
против CFoo<A>&
. В этом разделе есть и другие правила, но в конечном итоге этот вывод преуспевает с Q == A
.
Обе другие попытки не срабатывают по той же причине. Я заеду проще один:
template <class Q>
operator typename std::enable_if<1, CFoo<Q>&>::type const;
Здесь мы пытаемся вывести typename std::enable_if<1, CFoo<Q>&>::type
. Это не выведенный контекст (это вложенный имя-спецификатор типа, который был указан с использованием идентификатора ), поэтому вывод не выполняется. Таким образом, эта функция преобразования не будет рассматриваться, поэтому присваивание не выполняется, поскольку преобразование не найдено.
Вам нужен тип возвращаемого быть выведен контекст, поэтому SFINAE должен идти здесь:
template <class Q,
typename = std::enable_if_t<std::is_base_of<Q, T>::value>>
operator CFoo<Q>& const;
Таким образом, у нас есть что-то вывести (CFoo<Q>&
) - и вычет может быть успешным (если Q
является основой T
):
CFoo<A>& a = b; // OK
CFoo<int>& i = b; // deduction failure on Q, so there's no viable conversion function
// so this is an error
Тем не менее, в то время как я увлекся решение головоломок шаблона, а T.C. указывает, что это действительно не является хорошим решением, потому что:
return *(CFoo<Q>*)this;
просто делает reinterpret_cast
(и const_cast
), так что на самом деле не может быть делать что-нибудь разумное, и вы почти наверняка (если CFoo
не тривиальна) в конечном итоге с неопределенным поведением, пытаясь получить доступ к своим членам с неправильным типом.
Вы, вероятно, вместо этого нужно добавить Конверсиям конструктор вместо преобразования функции:
template <typename Q,
typename = std::enable_if_t<std::is_base_of<T, Q>::value>>
CFoo(CFoo<Q> const&) { }
Таким образом, когда вы делаете:
CFoo<A> a = b; // a is not a reference anymore
Вы строите новый объект, который обязательно будет действителен.
У этого _poof_ написано все это. –
'Q' не находится в выведенном контексте. Но почему вы это делаете? –
@ Капитан О. Я не понимаю! – johnnycrash