gpt4 book ai didi

c++ - std::is_same::value 总是为真吗?

转载 作者:可可西里 更新时间:2023-11-01 18:27:52 25 4
gpt4 key购买 nike

我继承了一些看起来像这样的代码:

///
/// A specializable function for converting a user-defined object to a string value
///
template <typename value_type>
std::string to_string(const value_type &value)
{
static_assert(!std::is_same<value_type, value_type>::value, "Unspecialized usage of to_string not supported");
return "";
}

///
/// A specializable function for converting a user-defined object from a string to a value
///
template <typename return_type>
return_type from_string(const std::string &source)
{
static_assert(!std::is_same<return_type, return_type>::value, "Unspecialized usage of from_string not supported");
}

!std::is_same<value_type, value_type>::value似乎过于冗长。

我是否应该将这些语句更改为 static_assert(false,"...")

我不确定以这种方式表达是为了处理某种边缘情况,还是 false确实是等价的。

std::is_same<t,t>::value总是正确的?

最佳答案

您发布的代码格式错误,无需诊断。

将其替换为 static_assert(false, ...)让编译器注意到您的代码格式不正确。之前的代码格式错误,只是编译器没有注意到它。

我有两个办法可以解决你的问题。一个是黑客,但合法。另一个更简洁,但需要您编写更多代码。

此答案的第一部分是您的代码格式错误的原因。接下来的两个是解决方案。

为什么代码格式错误?

template <typename value_type>
std::string to_string(const value_type &value)
{
static_assert(!std::is_same<value_type, value_type>::value, "Unspecialized usage of to_string not supported");
return "";
}

to_string的主模板不能用任何类型实例化。 C++ 标准要求所有模板(包括主模板)都必须具有有效的实例化(在标准语中称为有效特化)。 (还有其他要求,例如如果涉及包,则至少有一个这样的实例必须具有非空包等)。

您可能会提示“编译成功”,但那是不需要诊断的意思。 C++ 标准对编译器在遇到“格式错误且无需诊断”情况下的操作设置 约束。它可能无法检测到它并愉快地编译“有效”。它可以假定这是不可能的,并且如果确实发生了则生成格式错误的代码。它可以尝试检测它,失败,然后执行上述任一操作。它可以尝试检测它,成功并生成错误消息。它可以检测到并成功生成代码,将您去年在浏览器中查看的每张图片的缩略图通过电子邮件发送给您的所有联系人。

它的格式不正确,不需要诊断。

我自己会避免这样的代码。

现在,有人可能会争辩说有人可以在某个地方专攻 is_same<T,T>返回 false ,但这也会使您的程序格式错误,因为它是来自 std 的模板的非法特化。违反了标准中对模板的要求。

替换 !std::is_same<value_type, value_type>::valuefalse只会让您的编译器意识到您的代码格式错误,并生成一条错误消息。从某种意义上说,这是一件好事,因为格式错误的代码将来可能会以任意方式中断。

破解方法来修复它

解决这个问题的愚蠢方法是创建

template<class T, class U>
struct my_is_same:std::is_same<T,U> {};

承认特化漏洞的可能性。这仍然是代码味道。

修复它的正确方法

正确地编写这两种方法需要一些工作。

首先,to_stringfrom_string基于标签调度而不是模板特化:

namespace utility {
template<class T>struct tag_t {};
template <typename value_type>
std::string to_string(tag_t<value_type>, const value_type &value) = delete;
template <typename value_type>
std::string to_string(const value_type &value) {
return to_string(tag_t<value_type>{}, value);
}

template <typename return_type>
return_type from_string(tag_t<return_type>, const std::string &source) = delete;
template <typename return_type>
return_type from_string(const std::string &source) {
return from_string(tag_t<return_type>{}, source);
}
}

目标是最终用户只需执行 utility::from_string<Bob>(b)utility::to_string(bob)并且有效。

基本的会反弹到标签分派(dispatch)。要自定义,您需要重载 tag-dispatch 版本。

要在 Bob 的命名空间中实现 to/from 字符串编写这两个函数:

Bob from_string( utility::tag_t<Bob>, const std::string& source );
std::string to_string( utility::tag_t<Bob>, const Bob& source );

注意它们不是模板或模板的特化。

处理 std 中的类型或内置类型,只需在 namespace utility 中定义类似的重载.

现在,ADL 和标记分派(dispatch)将带您到正确的 to/from 字符串函数。无需更改 namespace 来定义到/从字符串。

如果您调用 to_stringfrom_string没有有效的 tag_t过载,你最终会调用 =delete并收到“未找到过载”错误。

测试代码:

struct Bob {
friend std::string to_string( utility::tag_t<Bob>, Bob const& ) { return "bob"; }
friend Bob from_string( utility::tag_t<Bob>, std::string const&s ) { if (s=="bob") return {}; exit(-1); }
};

int main() {
Bob b = utility::from_string<Bob>("bob");
std::cout << "Bob is " << utility::to_string(b) << "\n";
b = utility::from_string<Bob>( utility::to_string(b) );
std::cout << "Bob is " << utility::to_string(b) << std::endl;
Bob b2 = utility::from_string<Bob>("not bob");
std::cout << "This line never runs\n";
(void)b2;
}

Live example .

(不需要使用 friend,该函数只需与 Bob 位于相同的命名空间中或位于 namespace utility 内)。

关于c++ - std::is_same<t,t>::value 总是为真吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44847559/

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