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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With