在编译时确定参数的唯一性
Determine uniqueness of parameters at compile time
问题
我有以下类似数组的容器:
template <
class _Tp,
size_t _Size
> class Alphabet {
public:
template <class... _Ts>
constexpr
Alphabet(_Ts&& ... ts)
: m_data(std::forward<_Ts>(ts)...})
{}
private:
_Tp m_data[_Size ? _Size : 1];
}
我用的是这样的:
constexpr Alphabet<char, 3> abc{'a', 'b', 'c'}; // ok, elements are distinct
但是,我希望能够在编译时告诉元素是否是唯一的。因此,在构造函数的主体中,我只需简单地添加:
Alphabet(_Ts&& ... ts)
: m_data{std::forward<_Ts>(ts)...}
{
static_assert(is_unique(ts...), "Elements must be distinct!")
}
所以现在当我写:
constexpr Alphabet<char, 3> abc{'a', 'b', 'b'}; // error! elements are not distinct
我所尝试的
为此,我编写了以下代码,可在运行时使用:
template <class _Tp>
constexpr
bool is_one_of(_Tp)
{
return false;
}
template <class _Tp, class... _Ts>
constexpr
bool is_one_of(_Tp t, _Tp f, _Ts... ts)
{
return (t == f) || is_one_of(f, ts...);
}
template <class _Tp>
constexpr
bool is_unique(_Tp)
{
return true;
}
template <class _Tp, class... _Ts>
constexpr
bool is_unique(_Tp t, _Ts... ts)
{
return is_unique(ts...) && !is_one_of(t, ts...);
}
不幸的是,在尝试编译时,我很快就遇到了以下错误:
error: non-constant condition for static assertion
static_assert(detail::is_unique(ts...),
^
error: 'ts#0' is not a constant expression
我正在使用C++14。感谢您的帮助!
如果要检查ts...
值编译时(static_assert()
(,则必须将它们作为编译时已知的值传递。
不能在编译时检查constexpr
构造函数的参数,因为该构造函数也可以与运行时值一起使用。
我的建议是将ts...
值作为模板参数传递,因此它们是已知编译时的,因此您可以在static_assert()
测试中检查它们。
例如:如果Tp
是整数类型,则可以将它们作为std::integer_sequence
的参数传递
template <Tp ... Ts>
constexpr Alphabet (std::integer_sequence<Tp, Ts...> const &)
: m_data{Ts...}
{ static_assert( sizeof...(Ts) <= Size
&& are_unique<Ts...>(), "!" ); }
关于are_unique()
,我提出了一个递归版本
// ground case
template <typename = void>
static constexpr bool are_unique ()
{ return true; }
// recursive case
template <Tp T0, Tp ... Ts>
static constexpr bool are_unique ()
{ return is_unique<T0, Ts...>() && are_unique<Ts...>(); }
关于is_unique()
,您可以使用初始化unused
阵列的技巧
template <Tp T0, Tp ... Ts>
static constexpr bool is_unique ()
{
using unused = bool[];
bool ret = true;
(void)unused{ false, ret &= T0 != Ts... };
return ret;
}
如果你不喜欢每次都写std::integer_sequence
部分,你可以在make_Alphabet()
模板函数中只写一次
template <typename Tp, Tp ... Ts>
constexpr Alphabet<Tp, sizeof...(Ts)> make_Alphabet ()
{ return { std::integer_sequence<Tp, Ts...>{} }; }
并按以下使用
constexpr auto abcd{ make_Alphabet<char, 'a', 'b', 'c', 'd'>() };
以下是一个完整的编译C++14示例
#include <utility>
#include <iostream>
template <typename Tp, std::size_t Size>
class Alphabet
{
private:
Tp m_data[Size ? Size : 1U];
template <Tp T0, Tp ... Ts>
static constexpr bool is_unique ()
{
using unused = bool[];
bool ret = true;
(void)unused{ false, ret &= T0 != Ts... };
return ret;
}
// ground case
template <typename = void>
static constexpr bool are_unique ()
{ return true; }
// recursive case
template <Tp T0, Tp ... Ts>
static constexpr bool are_unique ()
{ return is_unique<T0, Ts...>() && are_unique<Ts...>(); }
public:
template <Tp ... Ts>
constexpr Alphabet (std::integer_sequence<Tp, Ts...> const &)
: m_data{Ts...}
{ static_assert( sizeof...(Ts) <= Size
&& are_unique<Ts...>(), "!" ); }
};
template <typename Tp, Tp ... Ts>
constexpr Alphabet<Tp, sizeof...(Ts)> make_Alphabet ()
{ return { std::integer_sequence<Tp, Ts...>{} }; }
int main()
{
// compilation error (static_assert failed "!")
//constexpr Alphabet<char, 3>
// aba{std::integer_sequence<char, 'a', 'b', 'a'>{}};
// compile
constexpr Alphabet<char, 3>
abc{std::integer_sequence<char, 'a', 'b', 'c'>{}};
// compilation error (static_assert failed "!")
//constexpr auto abca{ make_Alphabet<char, 'a', 'b', 'c', 'a'>() };
// compile
constexpr auto abcd{ make_Alphabet<char, 'a', 'b', 'c', 'd'>() };
}
相关文章:
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 使用指向成员的指针将成员函数作为参数传递
- 在编译时确定参数的唯一性
- 检查可变参数模板参数的唯一性