问题
In my infinite quest to push limits of what can be used as non type template parameter I was trying to see if I can use std::source_location
as non type template parameter.
That failed with a weird message, since I presume source_location is some magical struct...
type 'std::experimental::source_location' of non-type template parameter is not a structural type
It failed, so I tried to workaround that with using .file_name, but that also fails (godbolt).
note: candidate template ignored: substitution failure: pointer to subobject of string literal is not allowed in a template argument
#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();
}
Is there any way to make this work without use of macros?
To be clear I am asking about using source_location
as template parameter, not about solving my toy example, it is just here to demonstrate potential use case.
回答1:
std::source_location is specified as:
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
};
And the rules for the kinds of types that can be used as non-template template parameters require that a type be structural, which means, from [temp.param]/7, emphasis mine:
A structural type is one of the following:
- a scalar type, or
- an lvalue reference type, or
- a literal class type with the following properties:
- all base classes and non-static data members are public and non-mutable and
- the types of all bases classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.
source_location
does not have all of its non-static data members public, so it is not structural, so it is not usable as a non-type template parameter.
This part:
template <auto src_loc = std::experimental::source_location::current().file_name()>
does not work because of [temp.arg.nontype]/3:
For a non-type template-parameter of reference or pointer type, or for each non-static data member of reference or pointer type in a non-type template-parameter of class type or subobject thereof, the reference or pointer value shall not refer to or be the address of (respectively):
- [...],
- a string literal object ([lex.string]),
- ...
But what you can do is create your own type, that is structural, that is constructible from source_location
. It's just that the strings can't be char const*
, they have to own the data. If you look in the examples in P0732, we can build up:
template <typename Char, size_t N>
struct basic_fixed_string { ... };
template <basic_fixed_string S> struct A {};
using T = A<"hello">;
That might be awkward to deal with in this case, so you could also just pick some reasonable max size and go with that.
来源:https://stackoverflow.com/questions/65203441/stdsource-location-as-non-type-template-parameter