禁用默认模板,仅通过sfinae使用专业化
Disable default template and only use specialization through sfinae
考虑以下系统:
template<typename T>
struct wrapper
{
operator T * () { return nullptr; }
};
template<typename Ret, typename T>
Ret func(T);
template<>
int func(float * in)
{
std::cout << "long";
}
template<>
long func(float * in)
{
std::cout << "int";
}
包装器的目的是允许它衰减到模板化的类型(它是该类型缓冲区周围的包装器)。此外,我有一组函数,它们是模板的模板化专门化。这是为了避免在仅基于返回类型进行重载时出现的常见错误。
但这不起作用,正如这里所指出的:
// the following should work, but doesn't because it's instantiating
// the func<ret, wrapper<float>> which doesn't exist resulting in a linker error
// instead of selecting the int func(float *) overload
wrapper<float> w;
func<int>(w);
相反,我希望它生成一个编译时错误(但同样,它生成了一个链接时错误):
// the following should generate a compile-time error
// since no explicit overload for int func(int *) exists
wrapper<int> w2;
func<int>(w2);
因此,理想情况下,我想禁用原始模板(如果可能的话,可以通过sfinae?),这样重载解决方案只考虑显式专业化,如果找不到匹配,则会生成编译时错误。这能做到吗?
clang和msvc之间的可移植解决方案是必须的,但我使用的是两者的最新版本。
另一种方法可能是使用static_assert:
template<typename Ret, typename T>
Ret func(T) {
static_assert(false, "template specialization required");
}
如果进行
template<typename Ret> Ret func(float*);
它按预期工作:实例
虽然Jarod的答案解决了其中一个问题,但我仍然需要一种方法来重载函数参数(在这种情况下会产生"无匹配模板"错误)-我可能没有在OP中说明这一点。
我突然意识到,参数类型总是依赖于返回类型。然后我可以构建一个辅助结构,它将执行sfinae:
template<typename T>
struct option_of;
template<>
struct option_of<int>
{
typedef float value;
};
template<>
struct option_of<long>
{
typedef double value;
};
然后默认模板看起来是这样的:
template<typename Ret>
Ret func(typename const option_of<Ret>::value *);
然后过载可以这样构建:
template<>
int func(const float * in)
{
std::cout << "long";
}
template<>
long func(const double * in)
{
std::cout << "int";
}
-没有问题。请注意,返回和参数类型的任何其他组合都是无效的(因为它们不是原始模板的专门化,它只考虑我给它的选项)。这也将仅有的过载分辨率减少为两个过载,从而使这成为可能:
wrapper<float> w;
func<int>(w); // works
func<long>(w); // invalid, because no combination of long and float exists according to option_of
wrapper<int> w2; // works, but
func<int>(w2); // invalid because option_of doesn't consider int's
当然,额外的好处是编译器在调用/实例化时用正确的错误消息识别错误,而不是一些随机的静态断言/链接器错误。成功
相关文章:
- 如何使用默认参数等选择模板专业化
- 模板化建造师专业化
- 为什么使用SFINAE而不是函数重载
- 类模板的成员功能的定义在单独的TU中完全专业化
- 如何使用模板函数的函数签名进行SFINAE
- 数据成员SFINAE的C++17测试:gcc vs clang
- 使用在用于SFINAE的void_t中具有参数的方法
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 提供与TMP和SFINAE的通用接口
- 部分专业化和嵌套模板
- 模板专业化可以进入我的.cpp吗?
- "Inverse SFINAE"避免模棱两可的过载
- 别名模板的专业化 C++11 中没有开销的最佳替代方案
- 是否可以混合使用SFINAE和模板专业化?
- 使用void_t的多个SFINAE类模板专业化
- 部分模板专业化 SFINAE
- 部分专业化和SFINAE
- variadic模板专业化,std :: enable_if,sfinae
- 使用 SFINAE、约束或概念限制专业化
- 禁用默认模板,仅通过sfinae使用专业化