代码之家  ›  专栏  ›  技术社区  ›  bmk

“nullopt”能否作为非类型模板参数传递?

  •  5
  • bmk  · 技术社区  · 6 年前

    考虑以下代码示例

    #include <iostream>
    #include <experimental/optional>
    
    std::experimental::optional<int> dflt(42);
    
    template<const std::experimental::optional<int>& Dflt>
    void foo() {
        if (Dflt) {
            std::cout << "default is set" << std::endl;
        } else {
            std::cout << "default is not set" << std::endl;
        }
    }
    
    int main() {
            foo<dflt>();                       // <-- OK
            foo<std::experimental::nullopt>(); // <-- NOT OK
    }
    

    我想要达到的是通过考试 nullopt 作为非类型函数模板参数,但它不编译。它与全局变量一起工作 dflt 不过是静态存储。

    编译器错误消息如下所示:

    foo.cc: In function ‘int main()’:
    foo.cc:13:34: error: no matching function for call to ‘foo()’
      foo<std::experimental::nullopt>();
                                      ^
    foo.cc:7:6: note: candidate: template<const std::experimental::fundamentals_v1::optional<int>& Dflt> void foo()
     void foo() {
          ^
    foo.cc:7:6: note:   template argument deduction/substitution failed:
    foo.cc:13:34: error: could not convert template argument ‘std::experimental::fundamentals_v1::nullopt’ to ‘const std::experimental::fundamentals_v1::optional<int>&’
      foo<std::experimental::nullopt>();
    

    我知道这个例子很傻,但我的主要问题是,你能 nullopt 是否完全作为非类型模板参数传递?

    2 回复  |  直到 6 年前
        1
  •  6
  •   StoryTeller - Unslander Monica    6 年前

    不是你试图通过它的方式。

    较长的答案与模板参数上的约束有关。模板参数为引用类型。它的相应参数必须满足中的要求 [temp.arg.nontype]/2 (重点矿山):

    非类型模板参数的模板参数应为 已转换模板参数类型的常量表达式。 对于引用或指针类型的非类型模板参数 常量表达式的值 不应参考 (或指针 类型,不应是的地址):

    • 子对象,
    • 临时对象 ,则,
    • 字符串文字,
    • typeid表达式的结果,或
    • 预定义的 ­ func\uuuu变量。

    nullopt 是类型的常量 nullopt_t 。这显然不是 optional<int> 。因此,要绑定const引用,我们需要具体化一个临时的。但正如粗体文本所示,这显然会导致程序格式错误。


    但是请注意,您可以将参数作为 nullopt\u t 。然后你可以通过 nullopt 对于论点。虽然这样一个模板的实用性是有限的,我想说。

        2
  •  3
  •   Martin Bonner supports Monica    6 年前

    编辑:非类型模板参数的可用范围非常有限。基本上是整数/枚举或指向成员/引用的指针/指针。

    Story Teller 的回答解释了 为什么? 。修复方法是创建正确类型的命名常量:

    #include <iostream>
    #include <experimental/optional>
    
    std::experimental::optional<int> dflt(42);
    std::experimental::optional<int> nothing(nullopt);
    
    template<const std::experimental::optional<int>& Dflt>
    void foo() {
        if (Dflt) {
            std::cout << "default is set" << std::endl;
        } else {
            std::cout << "default is not set" << std::endl;
        }
    }
    
    int main() {
            foo<dflt>();    // <-- OK
            foo<nothing>(); // <-- Should be fine.
    }