2

在我无限探索可用作非类型模板参数的限制时,我试图查看是否可以std::source_location用作非类型模板参数。这失败了一个奇怪的消息,因为我认为 source_location 是一些神奇的结构......

非类型模板参数的类型“std::experimental::source_location”不是结构类型

它失败了,所以我尝试使用 .file_name 来解决这个问题,但这也失败了(godbolt)。

注意:候选模板被忽略:替换失败:模板参数中不允许指向字符串字面量子对象的指针

#include<iostream>
#include<experimental/source_location>

template<auto src_loc = std::experimental::source_location::current().file_name()>
void log_first(){
    static bool dummy =([]{
        std::cout << "Logging first call" + src_loc << std::endl;
    }(), false);
}

int main() {
    log_first();
    log_first();
}

有没有办法在不使用宏的情况下完成这项工作?

需要明确的是,我问的是source_location用作模板参数,而不是解决我的玩具示例,它只是为了演示潜在的用例。

4

1 回答 1

3

std::source_location被指定为:

  struct source_location {
    // ...

  private:
    uint_least32_t line_;               // exposition only
    uint_least32_t column_;             // exposition only
    const char* file_name_;             // exposition only
    const char* function_name_;         // exposition only
  };

并且可以用作非模板模板参数的类型的规则要求类型是结构的,这意味着,从[temp.param]/7 开始,强调我的:

结构类型是以下之一:

  • 标量类型,或
  • 左值引用类型,或
  • 具有以下属性的文字类类型:
    • 所有基类和非静态数据成员都是公共的和不可变的,并且
    • 所有基类和非静态数据成员的类型都是结构类型或其(可能是多维的)数组。

source_location它的所有非静态数据成员都不是公共的,因此它不是结构性的,因此不能用作非类型模板参数。


这部分:

template <auto src_loc = std::experimental::source_location::current().file_name()>

由于[temp.arg.nontype]/3 不起作用

对于引用或指针类型的非类型模板参数,或类类型或其子对象的非类型模板参数中的每个引用或指针类型的非静态数据成员,引用或指针值不应引用到或成为(分别)的地址:

  • [...],
  • 字符串文字对象([lex.string]),
  • ...

但是您可以做的是创建自己的类型,即结构类型,可从source_location. 只是字符串不能是char const*,它们必须拥有数据。如果您查看P0732中的示例,我们可以构建:

template <typename Char, size_t N>
struct basic_fixed_string { ... };

template <basic_fixed_string S> struct A {};

using T = A<"hello">;

在这种情况下,这可能很难处理,因此您也可以选择一些合理的最大尺寸并继续使用。

于 2020-12-08T17:04:29.010 回答