std::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">;
В данном случае с этим может быть неудобно иметь дело, поэтому вы также можете просто выбрать разумный максимальный размер и использовать его.