У меня есть класс, который в основном оборачивает std::variant
с некоторыми незначительными дополнительными функциями / метаданными.
Для простоты использования я хотел обеспечить пользовательское преобразование этого класса-обертки в базовый тип варианта, чтобы такие функции, как std::holds_alternative
, могли вызываться непосредственно из него.
То, что я обнаружил, очень меня смущает, когда и когда будут применяться определенные пользователем преобразования. Вот упрощенный код.
#include <iostream>
#include <variant>
struct MyClass
{
// "MyClass" is implicitly convertible to a variant<bool,int>
operator std::variant <bool, int> ()
{
return std::variant<bool,int>(5);
}
};
void thisFunctionTakesOneSpecificVariantType (std::variant<bool,int> v)
{
std::cout << v.index();
}
template <class... types>
void thisFunctionTakesAnyVariantType (std::variant<types...> v)
{
std::cout << v.index();
}
int main ()
{
MyClass mc;
// 1. This compiles and runs as expected,
// proving the user-defined conversion (MyClass -> variant<int,bool>) exists and works "sometimes"
thisFunctionTakesOneSpecificVariantType (mc);
// 2. This compiles and runs as expected,
// proving "thisFunctionTakesAnyVariantType" is well defined
thisFunctionTakesAnyVariantType (std::variant <bool, int> (5));
// 3. But, combining 1 & 2, this fails to compile:
/* fails */ thisFunctionTakesAnyVariantType (mc); // error: no matching function for call to 'thisFunctionTakesAnyVariantType'
// 4. This is what i really want to do, and it also fails to compile
/* fails */ std::holds_alternative<int>(mc); // error: no matching function for call to 'holds_alternative'
// 5. An explicit conversion works for 3 and 4, but why not an implicit conversion?
// After all, the implicit conversion worked in #1
thisFunctionTakesAnyVariantType ( static_cast<std::variant <bool, int>> (mc) );
return EXIT_SUCCESS;
}
Почему не используются компиляции прецедентов 3 и 4, а компиляции 1, 2 и 5?
В сообщениях об ошибках содержится это примечание:
note: candidate template ignored: could not match 'variant<type-parameter-0-1...>' against 'MyClass'
inline constexpr bool holds_alternative(const variant<_Types...>& __v)