问题
Ok, suppose I have this magic template
that takes a char
array and turns it into a template parameter list. For example: "thing"
is translated to list<'t','h','i','n','g'>
:
template<const char*, size_t>
ArrayToList;
You use it like this:
constexpr char string[] = "this is a test";
typedef ArrayToList<string,14> list;
Is there any way to somehow detect the string length implicitly so that all I have to do is:
typedef ArrayToList<string> list;
回答1:
Unfortunately, it can't be done:
You would like to have a non-type template parameter (the string). Syntactically speaking, the only way to specify a non-type template parameter is to declare its type, however, either the type depends on the length of the string itself and you need two template parameters (length and string), or if you convert the string to const char *
, the length of the string is lost in the parameter.
There are proposals to allow the capture of non-type template parameters whose type itself requires a template parameter to prevent forcing the syntax of those extra template arguments, like in your case.
I had the same kind of problem trying to capture pointers to members, it is necessary to also say what is the aggregate.
One recommendation: If you revert the order of the arguments to ArrayToList
, I think you can simplify the code by capturing the non-type parameter with its length, as here:
template<char...> struct list {};
// just a declaration
template<char, typename> struct add_to_list;
// specializes for the case of a list of chars, to insert v
template<char v, char... pack> struct add_to_list<v, list<pack...>> {
using type = list<v, pack...>;
};
// captures str[length - rindex] into the head of the list
template<unsigned rindex, unsigned length, const char str[length]>
struct to_list {
using type = typename add_to_list<
str[length - rindex],
typename to_list<rindex - 1, length, str>::type
>::type;
};
// base of the recursion
template<unsigned length, const char str[length]>
struct to_list<1, length, str> {
using type = list<>;
};
template<unsigned string_length, const char str[string_length]>
using ArrayToList =
typename to_list<string_length, string_length, str>::type;
// now, an example
constexpr char str[] = "hello";
template<typename> struct show_type_in_error;
show_type_in_error<ArrayToList<sizeof(str), str>> error;
来源:https://stackoverflow.com/questions/37892646/take-the-length-of-a-string-implicitly-in-templates