因此,我设计了一种my_numeric_cast
函数来限制使用我编写的框架时可用的转换类型。
做
之类的事情非常简单template<typename To, typename From>
constexpr To my_numeric_cast(From);
template<>
constexpr float my_numeric_cast<float, int>(int i) { return i; }
哪种方法有效,只允许在使用演员表时从整体中进行浮动。并且每当尝试不在白名单中的演员表时产生链接错误。
但是,我真的想把这个编译错误,以便更快地捕获误用。
如何使基本模板体有效,在实例化时期望它?
答案 0 :(得分:9)
你不能编写一个模板函数专门化,没有模板参数使得主体在C ++中有效。如果这样做的结果是形成错误的程序,不需要诊断。这包括主要专业化。
所以这里的大部分答案都是未定义的行为。它们可能有效,但它们不是有效的C ++。它们可能在今天工作,但在库升级后,编译器升级或不同的构建目标可能会以完全不同且令人惊讶的方式失败。没有强烈理由依靠UB是一个坏主意。
从好的方面来说,我们可以取消模板专业化并一举解决您的问题:
template<class T>struct tag_t{}; // may need `constexpr tag_t(){}` on some compilers
template<class T>constexpr tag_t<T> tag{};
template<class T, class F>
constexpr T my_numeric_cast(F, tag_t<F>)=delete; // generates compile time error
constexpr float my_numeric_cast(int i, tag_t<float>) { return i; } // not a template! Could be if you want it to be.
template<typename To, typename From>
constexpr To my_numeric_cast(From f){
return my_numeric_cast(f, tag<To>);
}
并完成。
=delete
生成友好消息。计划形成良好。实施演员表不再是专业化。您甚至可以在启用ADL的类型的命名空间中实现它。
如果您解决了模板功能专业化的问题,请重新考虑。它们很脆弱,不像类模板特化或函数重载那样工作(看起来像它们两个!),通常不是最好的解决方案。有一些例外,它可能是一个好主意,但它们是非常罕见的,并且考虑到它们避免古怪特征的罕见性可能仍然值得。
答案 1 :(得分:3)
您可以使用traits来获取编译时错误:
template<typename, typename> struct RetTraits;
// Enable it for int -> float
template<> struct RetTraits<int, float> { using type = float; };
template<typename To, typename From>
using RetType = typename RetTraits<To, From>::type;
template<typename To, typename From>
constexpr RetType<To, From> my_numeric_cast(From f) {
return To(f);
}
int main() {
my_numeric_cast<int, float>(42);
// This won't compile
// my_numeric_cast<int, int>(42);
}
答案 2 :(得分:0)
这是一个更新的答案,适用于pre c ++ 11代码。我仍然觉得 Yakk 的答案非常棒,以及他对功能模板专业化的建议,但我觉得我应该发布这个完整性。
如果理解正确,此解决方案不会导致程序格式错误,甚至会给出相当明确的错误消息。 它利用了使用类模板将主模板标记为不完整的概念,但仍使用函数模板特化。
namespace detail {
template<typename T1, typename T2> struct InvalidInstantiation;
}
template<typename To, typename From>
To my_cast (From f) {
detail::InvalidInstantiation<To, From> No_Function_Exists;
}
template<>
float my_cast(int i) { return i; }
int main() {
my_cast<float>(7);
//my_cast<int>(7.0); // This will result in an error
return 0;
}