您发布的代码格式不正确,无需诊断。
替换为static_assert(false, ...)
使编译器请注意您的代码格式不正确。代码was以前格式不正确,编译器只是没有注意到它。
我对你的问题有两个解决办法。一种是黑客攻击,但合法。另一个更干净,但需要您编写更多代码。
这个答案的第一部分是为什么你的代码格式不正确。接下来的两个是解决方案。
为什么代码格式错误?
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++ 标准位置zero当编译器遇到“格式错误,无需诊断”的情况时,对编译器执行操作的限制。它可能无法检测到它并愉快地编译“有效”。它可以假设这是不可能的,如果确实发生,则生成格式错误的代码。它可以尝试检测它,失败,然后执行上述任一操作。它可以尝试检测它、成功并生成错误消息。它可以检测到它,成功并生成代码,将您去年在浏览器中查看的每张图像的缩略图通过电子邮件发送给您的所有联系人。
它的格式不正确,不需要诊断。
我自己会避免这样的代码。
现在,有人可能会说有人可以在某个地方专门研究is_same<T,T>
回来false
,但这也会使您的程序形成错误,作为模板的非法专业化std
违反了标准中对模板的要求。
更换!std::is_same<value_type, value_type>::value
with false
只会让你的编译器意识到你的代码格式不正确,并生成错误消息。从某种意义上说,这是一件好事,因为格式不正确的代码将来可能会以任意方式破坏。
修复它的黑客方法
解决这个问题的愚蠢方法是创建
template<class T, class U>
struct my_is_same:std::is_same<T,U> {};
这承认了专业化漏洞的可能性。这仍然是代码味道。
正确的修复方法
编写这两个内容的正确方法需要做一些工作。
First, to_string
and from_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)
or utility::to_string(bob)
它有效。
基础的反弹到标签调度。要自定义,您可以重载标签调度版本。
要实现 to/from 字符串,在命名空间中Bob
写出这两个函数:
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 和标签分派将带您到正确的字符串函数。无需更改名称空间来定义字符串。
如果你打电话to_string
or from_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;
}
实例 http://coliru.stacked-crooked.com/a/acac84a7656b9def.
(Use of friend
不是必需的,该函数只需与以下函数位于同一名称空间中即可Bob
或之内namespace utility
).