用户定义的转换不适用于可变参数函数参数?为什么不呢?
User-defined conversions aren't applied to variadic function arguments? Why not?
我有一个类,它主要用一些次要的附加功能/元数据包装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)
为什么用例 3 不编译
由于模板参数推导中不考虑隐式转换:
类型推断不考虑隐式转换(上面列出的类型调整除外(:这是重载解决的工作,稍后会发生。
从MyClass
到std::variant <bool, int>
的转换将不考虑,然后类型扣除失败。如 #5 所示,您可以在传递到thisFunctionTakesAnyVariantType
之前应用显式转换。
为什么用例 4 不编译
与#3的原因相同。请注意,即使您为参数包指定了一些模板参数 模板参数推导 仍然会尝试从函数参数中推导出以下模板参数。您可以使用从扣除中排除函数参数作为
template <class... types>
void thisFunctionTakesAnyVariantType (std::type_identity_t<std::variant<types...>> v)
然后你可以称之为
thisFunctionTakesAnyVariantType<bool, int>(mc);
但请注意,这将使所有模板参数推导无效(#2 和 5 将失败(,因此这可能是一个坏主意。
顺便说一句:自 C++20 以来std::type_identity
受到支持,即使很容易实现。
这就是规则的制定方式。其他比我更有知识的人可能会来给你这里的确切规则(考虑模板替换和转换(,但归根结底就是这样,你无法改变它。
为了考虑转换,您的类需要从std::variant<int, bool>
继承。您的所有示例都将编译。然而,我不愿意推荐这种方法,因为构图在这里似乎是正确的设计。
我要做的是提供一种转换方法。你失去了它的隐含方面,但也许这不是一个坏主意,至少考虑替代方案。
struct MyClass
{
std::variant<bool, int> to_var() const
{
return {5};
}
}
thisFunctionTakesAnyVariantType (mc.to_var());
std::holds_alternative<int>(mc.to_var());
您可以将转换运算符保留在它起作用的那些情况下,但请考虑它是否不仅会增加混乱。
- 将可变参数函数的参数封装在类实例中
- QML 使用带有参数C++函数
- 使用可变参数函数作为模板参数
- 如何在C++中伪造虚拟可变参数函数模板?
- 为什么可变参数函数不适用于模板
- C++ std::functional 中的可变参数函数模板
- 可变参数函数指针的定义对于VxWorks spyLib来说不清楚
- 使用可变参数函数覆盖具有不同函数签名的虚函数
- 考虑引用和常量的可变参数函数包装器
- 使用可变参数函数将整数和/或整数数组放入单个 int 数组中
- 在可变参数函数中转发特定范围的参数
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 使用带有一个参数函数的递归找到数字的平方
- 可变参数函数模板不能很好地使用 std::function 作为参数
- 多个可变参数函数的单个模板参数包?
- 参数数据类型未知的可变参数函数
- 可变参数函数参数包扩展
- 使用模板可变参数函数将多个参数传递给另一个函数
- 对可变参数函数的递归调用的链接器错误
- 通过像printf这样的可变参数函数传递一个带有常量字符*转换函数的类