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();
}

Есть ли способ заставить это работать без использования макросов?

Чтобы было ясно, я спрашиваю об использовании как параметр шаблона, а не о решении моего игрушечного примера, он просто здесь, чтобы продемонстрировать потенциальный вариант использования.

1 ответ

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, акцент мой:

Структурный тип является одним из следующих:

  • скалярный тип или
  • ссылочный тип lvalue или
  • литеральный тип класса со следующими свойствами:
    • все базовые классы и нестатические члены данных являются общедоступными и неизменяемыми и
    • типы всех базовых классов и нестатических элементов данных являются структурными типами или (возможно, многомерными) их массивами.

не имеет общедоступных нестатических элементов данных, поэтому он не является структурным, поэтому его нельзя использовать в качестве параметра шаблона, отличного от типа.


Эта часть:

      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">;

В данном случае с этим может быть неудобно иметь дело, поэтому вы также можете просто выбрать разумный максимальный размер и использовать его.

Другие вопросы по тегам