gpt4 book ai didi

c++ - 在模板评估期间允许隐式类型转换

转载 作者:行者123 更新时间:2023-12-04 01:06:44 24 4
gpt4 key购买 nike

我正在为 C++ 类型编写一个包装器类,它允许我在构建、访问、修改和销毁包装对象时进行检测。为了使这对原始代码透明,我将隐式转换函数包含回基础类型,但是当包装对象直接传递给模板时这会失败,因为不评估隐式转换。下面是一些演示此问题的代码:

#include <utility>

// simplified wrapper class
template <typename T>
class wrap {
T t;
public:
wrap() : t() {}
wrap(const T& _t) : t(_t) {}
wrap(T&& _t) : t(std::move(_t)) {}

constexpr operator T&() { return t; }
constexpr operator const T&() const { return t; }
};

// an example templated function
template <typename T>
bool is_same(const T& t1, const T& t2) { return t1 == t2;}

// second invocation fails due to template substitution failure
bool problem() {
wrap<int> w(5);

return is_same(static_cast<int>(w), 5) && is_same<>(w, 5);
}

我可以通过在每个模板调用站点对包装变量执行 static_cast 手动解决此问题(如第一次调用所示),但这不能很好地扩展,因为我正在使用庞大的代码库。 Similar questions建议将每个模板函数内联为一个 friend 函数,但这也需要识别和复制每个模板,这不会缩放。

对于如何 (1) 使用模板函数解决此转换问题,或 (2) 以其他方式在源代码级别检测变量而不会出现此问题,我将不胜感激。

最佳答案

这个例子的错误在于is_same .它声明它需要两个相同类型的参数,这是它不需要的要求,并且不要求该类型具有 ==。 ,它确实需要。

诚然,C++ 对模板函数的约束很差是很常见的,因为否则这样做既困难又冗长。作者采取了一条实用的捷径。也就是说,这不是修复 is_same 接口(interface)的方法吗? ?

// C++17 version. Close to std::equal_to<>::operator().
template <typename T, typename U>
constexpr auto is_same(T&& t, U&& u)
noexcept(noexcept(std::forward<T>(t) == std::forward<U>(u)))
-> decltype(std::forward<T>(t) == std::forward<U>(u))
{
return std::forward<T>(t) == std::forward<U>(u);
}

修正了is_same ,代码正常工作。

人们可以想象还有其他示例可能需要两个参数具有相同的类型。例如,如果返回类型取决于参数类型并且返回值可以来自以下任一:

template <typename T>
T& choose(bool choose_left, T& left, T& right) {
return choose_left ? left : right;
}

这种情况要少得多。但它实际上可能需要考虑来决定是使用底层类型还是包装类型。如果您在包装器类型中具有这种增强行为,并且有条件地使用包装值或底层值,是否应该包装底层值以继续获得增强行为,或者我们是否放弃增强?即使你能让它默默地选择这两种行为中的一种,你愿意吗?

但是,您仍然可以使获取值比说 static_cast<T>(...) 更容易。 ,例如通过提供访问器:

// given wrap<int> w and int i
is_same(w.value(), 5);
choose_left(true, w.value(), i);

我还有一些重要的意见:

wrap() : t() {}

这要求 T 是默认可构造的。 = default做正确的事。

wrap(const T& _t) : t(_t) {}
wrap(T&& _t) : t(std::move(_t)) {}

这些不是明确的。 T可以隐式转换为 wrap<T>反之亦然。这在 C++ 中效果不佳。例如,true ? w : i格式不正确。这导致 std::equality_comparable_with<int, wrap<int>>为假,这将是 is_same 的合理要求.包装类型可能应该显式构造,并且可以隐式转换为基础类型。

constexpr operator T&() { return t; }
constexpr operator const T&() const { return t; }

这些不是引用限定的,因此即使包装器是右值,它们也会返回左值引用。这似乎是不明智的。

最后,构造和转换只考虑精确类型T .但是任何地方T被使用时,它可能从其他类型隐式转换而来。在 C++ 中不允许进行两次转换。因此,对于包装器类型,需要做出决定,这通常意味着允许从 T 的任何内容进行构造。可从.

关于c++ - 在模板评估期间允许隐式类型转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66181709/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com