如果我有这样的模板化结构:
template<typename T>
struct A {};
如何删除特定类型(例如void)的部分专业化,以便对A
template<>
struct A<void> = delete;
尽管我本质上想要与此类似的东西,但由于该语法不存在,所以编译不符合预期。
尽管我目前确实对此问题有一个“解决方案”,即删除所有可能的构造函数:
template<>
struct A<void> { template<typename...> A(...) = delete; };
但这不是最佳解决方案,因为用户只要不尝试实例化对象,仍然可以使用A
template<typename T, typename = typename std::enable_if<!std::is_same<T, void>::value>::type>
struct A {};
这很好用,可以做到,所以提到A
因此,除了我到目前为止提供的解决方案之外,还有什么好方法可以做到这一点;如果没有,是否可以改善当用户使用A 我可以使用c ++ 17和clang的c ++ 2a(如果它添加了任何有助于此操作的新功能)。 更新:正如@PicaudVincent在他的回答中所说,第二种解决方案不允许您根据条件限制所有类型,只能限制单个类型,但是有一种解决方法: 我们可以在struct A周围编写一个完美的包装器,也就是在Helper函数的帮助下,包装器的行为与原始类型完全相同 现在您可以使用B <>代替A <>,即使它们是同一事物,并且将以相同的方式运行,并在需要时将其转换为A <>,例如在调用带有在A <>中。 尽管如果函数使用B <>,则除非通过static_cast或类似方法将A <>明确转换为B <>,否则无法传递A <>。 这也适用于任何模板化类,您只需将A替换为您要使用的类,并用您的条件替换enable_if: 这不是最好的解决方案,但是它确实允许您现在必须更改原始声明,并且仍然可以限制可放入其中的内容,而不必手动命名每种类型。
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...>;
using B = Helper</*Structure to use*/,
typename std::enable_if</*Condition*/>::type,
Args...>;
答案 0 :(得分:2)
如果您确实想要“编译时”错误,则可以使用static_assert
。使用--std=c++14
进行编译的代码如下:
#include <type_traits>
template <typename T>
struct A
{
static_assert(!std::is_same<T, void>::value, "Not allowed");
};
int main()
{
A<double> a_d;
A<void> a_v; // <- compile time error
}
更新:
我了解您的评论。不幸的是:
template <>
struct A<void>
{
static_assert(false, "Not allowed");
};
不起作用,因为确定为false的条件并且编译器检测到了。
不确定在那种情况下我们能否找到基于static_assert
的解决方案。在我这一刻,我还没有找到一个。
更新2:Filipe Rodrigues自我解答
或者,只需定义struct A<void>
但不使用正文。
template<> struct A<void>;
然后输入如下代码:
int main()
{
A<double> a_d;
A<void> a_v;
}
触发这种错误:
aggregate ‘A<void> a_v’ has incomplete type and cannot be defined
1 /与2 /
2 /具有简单性的优点,但是使用1 /可以编写:
template <typename T>
struct A
{
static_assert(std::is_arithmetic<T>::value,
"A<T>, T: must be an arithmetic type");
};
这是您无法使用的2 /
答案 1 :(得分:1)
最后,有3种方法可以完成此任务,每种方法都有其起伏:
在结构的初始正文中,编写带有条件的static_assert
template<typename T>
struct A
{
static_assert(!std::is_same<T, void>::value);
...
}
优点:
缺点:
在没有主体的情况下定义专业化,从而阻止编译器使用该专业化
template<>
struct A<void>;
在尝试实例化对象时会给出这样的错误消息:
aggregate 'A<void> Var' has incomplete type and cannot be defined
优点:
缺点:
您可以编写一个帮助程序类,该类实际上将您要专门化的类型包装为具有无法控制的所有功能的新类型,因此您可以使用方法1对其进行自定义,甚至可以使用std :: enable_if。
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...) {};
static_assert(/*Condition*/);
};
template<typename...Args>
using B = Helper</*Type to wrap around*/,
typename std::enable_if</*Condition*/>::type,
Args...>;
优点:
缺点: