在推导函数参数时是否需要考虑隐式用户定义转换运算符() 的解决方法?

Con*_*ery 0 c++ templates types c++20

考虑以下示例,它尝试将 a 传递std::array给函数。当然不考虑“转换”,但是有没有不需要明确的解决方法?特别是如果该类已经提供了必要的属性(value_type 等)。

template <typename T, size_t N>
struct Array_t
{
    using value_type = T;
    using size_type = size_t;

    std::array<T, N> Internal{};

    constexpr operator auto() { return Internal; }
};

template <typename T, size_t N> constexpr bool Test(std::array<T, N> Input)
{
    return Input.size() == 32;
}

constexpr std::array<uint8_t, 32> OK1 = Array_t<uint8_t, 32>();
constexpr auto OK2 = Test((std::array<uint8_t, 32>)Array_t<uint8_t, 32>{});
constexpr auto OK3 = Test(Array_t<uint8_t, 32>().Internal);

// could not deduce template argument for 'std::array<_Ty,_Size>'
// from 'Array_t<uint8_t,32>'
constexpr auto FAIL = Test(Array_t<uint8_t, 32>{});
Run Code Online (Sandbox Code Playgroud)

为了澄清这一点,有一个解决方法,以便 Array_t 结构可以直接传递给任何需要 std::array 的函数。没有强制转换,没有辅助/转换函数,只是让编译器了解该结构是可转换的某种方式。可能与 CTAD 类似。

Bar*_*rry 5

模板推导从不考虑(用户定义的)转换。鉴于您的:

template <typename T, size_t N>
constexpr bool Test(std::array<T, N> Input);
Run Code Online (Sandbox Code Playgroud)

如果您在代码中看到 ,Test(x)那么只有在x是特定的某种类型std::array或继承(公开且明确)的情况下才有效。

如果您希望此方法起作用,您有几种不同的选择(按照我个人的偏好顺序):

  1. 您可以创建Test更广泛的函数模板,接受它实际可以使用的任何内容,而不仅仅是特定的std::array<T, N>。鉴于您说“特别是如果该类已经提供了必要的属性(value_type 等)”,这表明您想要的Test并不是专门的std::array. 因此,您应该弄清楚这些实际属性是什么,并编写一个适当约束的函数模板。例如,是否ranges::contiguous_range足够或者您实际上需要编译时大小吗?您甚至需要连续性吗?ETC。

  2. 您可以在调用方将您显式转换Array_t为 a 。std::array如果您为转换函数指定一个名称,效果会更好,这样您就可以编写类似obj.to_array()而不是的内容static_cast<std::array<T, N>>(obj)(这不仅需要输入更长的时间,而且使参数正确更烦人)。

  3. 您可以显式地向 提供必要的模板参数Test,例如Test<uint8_t, 32>(obj)- 这可以避免需要推导TN,现在您只有一个接受 a 的普通函数std::array<uint8_t, 32>,因此转换工作得很好。请注意,您必须同时提供两者Test<uint8_t>(obj)这是不够的。

  4. 您可以继承Array_t<T, N>std::array<T, N>,而不仅仅是转换为它。这立即生效。