【问题标题】:checking uniqueness of characters at compile time在编译时检查字符的唯一性
【发布时间】:2018-07-09 22:27:32
【问题描述】:

是否有可能在 C++11(不是以后)中编写一个函数来验证在编译时传递给它的字符的唯一性

verify('a');
verify('b');
verify('c');
verify('a');  //should cause compilation error

[由 MK 编辑回答一些问题]:

  • 调用总是在同一个范围内,像上面一样一个接一个。
  • 宏观解决方案也可以接受
  • 也可以接受非类型模板参数

【问题讨论】:

  • 这些电话之间的距离可以有多远?他们总是在同一个范围内吗?您对宏解决方案满意吗?
  • 还有,你打算用它做什么?
  • 如果字符作为模板非类型参数传递可以吗?我的意思是:verify<'a'>(); verify<'b'>(), verify<'c'>(), vefify<'a'>();
  • @GuillaumeRacicot - 永远不要低估 constexpr 的黑暗面的力量......我的意思是......也许你是对的,它太危险了。但真正的问题是我无法让它发挥作用。
  • 可能有一种类似于this的方式。

标签: c++ c++11 constexpr compile-time


【解决方案1】:
template<std::size_t X>
struct line_t { enum{value=X}; constexpr line_t(){} };

template<std::size_t line, char c>
constexpr std::integral_constant<bool, false> use_flag(
  std::integral_constant<char,c>, line_t<line>
) { return {}; }

#define FLAG_USE( C ) \
constexpr std::integral_constant<bool, true> use_flag( \
  std::integral_constant<char,C>, line_t<__LINE__> \
) { return {}; }

template<char c, std::size_t line>
constexpr std::size_t count_uses( line_t<line> from, line_t<1> length ){
  return use_flag( std::integral_constant<char, c>{}, from )();
}
template<char c, std::size_t line>
constexpr std::size_t count_uses( line_t<line> from, line_t<0> length ){
  return 0;
}

template<char c, std::size_t f, std::size_t l>
constexpr std::size_t count_uses(line_t<f> from, line_t<l> length ){
  return count_uses<c>( from, line_t< l/2 >{} )+ count_uses<c>( line_t< f+l/2>{}, line_t<(l+1)/2>{} );
}

#define UNIQUE(C) \
  FLAG_USE(C) \
  static_assert( count_uses<C>( line_t<0>{}, line_t<__LINE__+1>{} )==1, "too many" )

这应该适用于大小为 2^100 秒的文件,直到您的编译器内存不足,因为计数是对数深度递归。

line_t 类型启用延迟 ADL 查找 use_flag,直到我们调用 count_uses。我们对use_flag 的每个重载进行二叉树求和,文件中的每个字符每行一个。

Live example.

【讨论】:

  • 不错。您可以将 FLAG_USE 折叠成 UNIQUE,只留下一个 MACRO。作为一个难题,你能把它减少到没有吗?
  • @jive 你可以随时扩展它们。您确实需要 __LINE__ 来使用此技术。有一些危险的有状态元编程技术不需要__LINE__,但它们很脆弱,基本上依赖于标准缺陷。
【解决方案2】:

不完全是您要求的,但考虑到您的限制(相同的范围和宏解决方案是可以接受的),您可以尝试这样的事情:

#define verify(x) class _tmp_##x {};

例子:

int main()
{
    verify(a);
    verify(b);
    verify(a);
    return 0;
}

由于重新定义本地类_tmp_a,编译将失败。

【讨论】:

  • 又短又甜。
  • 这是一件美丽的事情
猜你喜欢
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多