【问题标题】:Is there an existing name for this type and function?这种类型和功能是否存在现有名称?
【发布时间】:2019-09-22 08:40:20
【问题描述】:

计算机科学中有 2 个难题:缓存失效、命名事物和非一错误。

这是关于第二个问题:命名。

我正在寻找这种技术或类型是否已经在其他地方使用过并且有名称。 dichotomy 是一个不错的名字,但 bools_at_compile_time 是一个可怕的名字。

using dichotomy_t = std::variant<std::false_type, std::true_type>;
// (or a struct that inherits from that, and overloads operator bool())

constexpr dichotomy_t dichotomy( bool b ) {
  if (b) return std::true_type{};
  return std::false_type{};
}
template<class F, class...Bools>
constexpr auto bools_at_compile_time( F&& f, Bools...bools ) {
  static_assert( (std::is_same<Bools, bool>{} && ...) );
  return std::visit( std::forward<F>(f), dichotomy(bools)... );
}

dichotomy_t 是真假之间的变体。它的运行时表示是01

这可以让你做的是:

auto foo( bool x, bool y ) { // <-- x and y are run-time bools here
  auto func = [&](auto x, auto y) {
    return some_template<x,y>(); // <-- x and y are compile-time bools here
  };
  return bools_at_compile_time( func, x, y ); // <-- converts runtime to compile time bools
}

dichotomy_t 或更通用的 bools_at_compile_time 技术有名称吗?我正在寻找一个在任何社区(甚至是非 C++ 社区)中都广为人知的名称,甚至是描述“获取运行时值并在生成的代码中创建开关和一组编译时间值以供选择的动词” "胜过一句话。

Live example

一个好的答案将包括名称、描述该名称含义的引用/引用、在其他上下文中使用的该命名事物的示例,以及该名称等同于或包含上述类型/值和功能的证据.

(找到一个名称可能会有所帮助,它的概括将是 enum 而不是 bool,它具有固定数量的已知状态,以及将运行时值转换为每个 case 子句中的编译时常量。)

【问题讨论】:

  • 我正试图了解这实际上是做什么的。它基本上是围绕 bool b = ...; if (b) func&lt;true&gt;(...); else func&lt;false&gt;(...); 之类的包装吗? (但对于多个布尔值的所有组合)
  • @NicolBolas 他们有一个constexpr operator bool,它不依赖于在编译时评估的*thisconstexprness。因此,虽然 x 不是 constexpr 值,但 static_cast&lt;bool&gt;(x) 常量表达式,这就是将它传递给模板的作用。它适用于当前所有主要的编译器;不是在一些旧的。
  • @André 是的,但这似乎是个坏主意。不,似乎不是。是。这是个坏主意。 (并且编译器在实践中到达那里之前会窒息)。而且一般有2^32不同的32位整数,没有-1。但是,是的,类似的技术可以轻松地从O(n) 代码创建O(2^n) 程序集;除了小的n,不建议这样做。但这是一个次要问题;我正在寻找一个已在其他地方使用过的 name
  • 我会说 dispatcher,即使可能过于笼统。
  • 我以前听说过在这种情况下使用“提升”。将运行时值提升为类型。

标签: c++ boolean c++17 variant


【解决方案1】:

您的问题是:(我的粗体字)

我正在寻找一个在任何社区都广为人知的名字(即使是 非 C++ 之一),甚至是描述“获取运行时值和 在生成的代码中创建一个开关和一组编译时间值以 在”之间选择比一个句子更好。

有,但前提是你会从相关科学领域采用它:

美国国家电气规范 (NEC) 将配电盘定义为“一个 大型单面板、框架或安装在其上的面板组件, 在面部,背部,或两者,开关,过电流和其他 保护装置、总线,通常还有仪器”。 配电盘是允许提供给的电流的划分 配电盘成更小的电流,以便进一步分配和 提供开关、电流保护和(可能)计量 那些不同的电流。一般来说,配电盘可以分配电力 到变压器、配电板、控制设备,并最终到 单独的系统负载。

采用这种思想,您可以简单地将其称为switches

我还要补充一点,在类型/变量名称中指定(即重复)存储类型或 cv 限定符等是非常不寻常的——即使在不直接可见的情况下,您通常也会这样做将其保留为隐含的-除非确实需要强调。

【讨论】:

    【解决方案2】:

    由于我不知道有类似的实现,我将逐个类型地使用自行车棚颜色。


    using boolean_t = std::variant<std::false_type, std::true_type>;
    

    这是不言自明的,因为它是一种变体,可以存储 std::integral_constants 中的一个或另一个来判断真假。有点像bool,但bool_t 可能会引起混淆。另一种选择是boolean_variant,但这可能太冗长了。


    constexpr boolean_t to_boolean_t( bool b ) {
      if (b) return std::true_type{};
      return std::false_type{};
    }
    

    我从convert_bool 开始,但这有点太笼统了。 to_boolean_t 更具表现力。 make_boolean_t 也是一种可能性,因为它基本上是 boolean_t 工厂函数。注意:我之前选择了to_constexpr_boolean,但这太冗长了。


    template<class F, class...Bools>
    constexpr auto static_eval( F&& f, Bools...bools ) {
      static_assert( (std::is_same<Bools, bool>{} && ...) );
      return std::visit( std::forward<F>(f), to_boolean_t(bools)... );
    }
    

    我在这里选择了static_eval,因为我喜欢 Clonk 的推理,但“静态”在 C++ 中具有上下文含义,因此替代方案是(按重要性不分先后):

    • boolean_visit
    • static_visit
    • constexpr_eval
    • constexpr_visit

    【讨论】:

      【解决方案3】:

      生成一个函数的专用版本称为克隆。 (见Procedure Cloning)。 clone 一词用于命名优化器在常量传播期间生成的专用函数(请参阅gcc doc)。

      std::visit 生成的专用函数集可以命名为克隆集

      这个集合是为所有combinations 的参数值生成的。这个术语组合让我们假设每个参数的可能值的集合是有限的。

      因此,我们可以为克隆集设置一个长名称,例如,所有参数值组合的克隆集。另一个更模糊但更短的选项可能是组合克隆集

      正如已经指出的,根据参数选择要调用的正确函数的动作可以称为dispatch

      所以我建议combinatiorial_clone_set_dispatchdispatch_in_combinatorial_clone_set ...

      【讨论】:

        【解决方案4】:

        也许是 staticCastValue? 正如您将动态(运行时)值转换为静态值一样。 可以与不同类型的模板或重载一起使用。

        或者可能是 assertInmutable? 就像您将可变类型转换为不可变类型一样。

        或者也许是不断地表达? 正如你在表达相同的价值但以不变的形式。 类似于 constexpr 的形式。

        狂野的: 静态分叉? 由于有两件事可供选择,因此存在分歧。

        分叉 动词 /ˈbʌɪfəkeɪt/ 1. 分成两个分支或叉子。 “就在开罗下方,河流分叉”

        或者最终convertToConstExpr? 明确表示该值将转换为与 constexpr 类似或兼容的值。

        【讨论】:

        • 可能是最后一次尝试,虽然可能有点傻:chrono_compilerize 就像你将值转换为编译时间兼容
        【解决方案5】:

        我不知道此模式的任何现有名称,但如果您仔细了解 STL 是如何命名事物的,您可以使用足够接近的名称来使您的代码明确。

        我也喜欢@Jarod42 的dispatcher_t 想法,我认为它比dichotomy_tn_chotomy_t 更通用。

        dichotomy() 可以称为make_variant(b)。因为它将返回参数中给出的布尔值的std::variant 值。很像 std::make_tuple 从多个参数创建一个元组。

        我建议将bools_at_compile_time 替换为static_eval。就像static_assert 在编译时做出断言一样。

        如果eval 不是您的用例的正确形容词,您可以轻松地调整它static_*

        #include <type_traits>
        #include <variant>
        #include <utility>
        
        using dichotomy_t = std::variant<std::false_type, std::true_type>;
        // (or a struct that inherits from that, and overloads operator bool())
        
        constexpr dichotomy_t make_variant( bool b ) {
          if (b) return std::true_type{};
          return std::false_type{};
        }
        template<class F, class...Bools>
        constexpr auto static_eval( F&& f, Bools...bools ) {
          static_assert( (std::is_same<Bools, bool>{} && ...) );
          return std::visit( std::forward<F>(f), make_variant(bools)... );
        }
        
        template<bool x, bool y>
        auto some_template() {
            return x || y;
        }
        
        auto foo( bool x, bool y ) { // <-- x and y are run-time bools here
          auto func = [&](auto x, auto y) {
            return some_template<x,y>(); // <-- x and y are compile-time bools here
          };
          return static_eval( func, x, y ); // <-- converts runtime to compile time bools
        }
        
        #include <iostream>
        
        int main() {
            std::cout << foo( true, true ) << "\n";
        }
        

        【讨论】:

        • static_assert 确实在编译时完成,static_eval 将在编译时仅在 const expr 上下文中完成(与任何 constexpr 函数一样)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多