【发布时间】:2018-07-07 09:38:57
【问题描述】:
如果我有这样的模板结构:
template<typename T>
struct A {};
如何删除特定类型的部分特化,例如 void,以便任何提及 A 都会导致编译器错误?
template<>
struct A<void> = delete;
这不会像预期的那样编译,因为这种语法不存在,尽管我本质上想要类似的东西。
虽然我目前对这个问题有一个“解决方案”,那就是删除所有可能的构造函数:
template<>
struct A<void> { template<typename...> A(...) = delete; };
但这不是最好的解决方案,因为用户仍然可以使用 A 只要他们不尝试实例化对象。我还尝试将 enable_if 添加到初始结构中:
template<typename T, typename = typename std::enable_if<!std::is_same<T, void>::value>::type>
struct A {};
这很好用,所以提到 A 会产生编译器错误(虽然有点夸张,因为它指的是 enable_if 本身),但如果我无法访问,这将不起作用初始定义,例如当专门化别人的结构时。
除了我目前的解决方案之外,还有什么好的方法可以做到这一点,如果没有,有没有办法改进当用户使用 A 时我必须给出编译器错误的方法?
我可以使用 c++17 和 clang 的 c++2a,如果它添加了任何有助于解决此问题的新功能。
更新:正如@PicaudVincent 在他的回答中所说,第二种解决方案不允许您根据条件限制所有类型,只能限制单一类型,但有一种解决方法:
我们可以为结构 A 编写一个完美的包装器,也就是说,在 Helper 函数的帮助下,包装器的行为与原始类型完全相同
template<template<typename...> class U, typename=void, typename...TArgs>
struct Helper : U<TArgs...>
{
using U<TArgs...>::U;
template<typename...Args>
Helper(Args...args) : U<TArgs...>(args...) {};
};
template<typename...Args>
using B = Helper<A,
typename std::enable_if<(... && std::is_arithmetic<Args>::value)>::type,
Args...>;
现在您可以使用 B 代替 A,即使它们是相同的东西,并且会以相同的方式运行,并且会在需要时转换为 A,例如在调用需要的函数时在 A.
虽然如果一个函数接受 B,你不能传递 A,除非你使用 static_cast 或类似的方法将 A 显式转换为 B。
这也适用于任何模板类,您只需将 A 替换为您尝试使用的类,并将 enable_if 替换为您的条件:
using B = Helper</*Structure to use*/,
typename std::enable_if</*Condition*/>::type,
Args...>;
这不是最好的解决方案,但它确实允许您现在必须更改原始声明并仍然限制您可以在其中放入的内容,而无需手动命名每种类型。
【问题讨论】:
-
使用 static_assert。
标签: c++ templates template-specialization