简体   繁体   中英

C++ Template const char array to int

So, I'm wishing to be able to have a static const compile time struct that holds some value based on a string by using templates. I only desire up to four characters. I know that the type of 'abcd' is int , and so is 'ab','abc', and although 'a' is of type char , it works out for a template<int v> struct

What I wish to do is take sizes of 2,3,4,5 of some const char, "abcd" and have the same functionality as if they used 'abcd'. Note that I do not mean 1,2,3, or 4 because I expect the null terminator.

cout << typeid("abcd").name() << endl; tells me that the type for this hard coded string is char const [5] , which includes the null terminator on the end.

I understand that I will need to twiddle the values as characters, so they are represented as an integer.

I cannot use constexpr since VS10 does not support it (VS11 doesn't either..)

So, for example with somewhere this template defined, and later the last line

template <int v> struct something {
    static const int value = v;
};

//Eventually in some method
cout << typeid(something<'abcd'>::value).name() << endl;

works just fine.

I've tried

template<char v[5]> struct something2 {
    static const int value = v[0];
}

template<char const v[5]> struct something2 {
    static const int value = v[0];
}

template<const char v[5]> struct something2 {
    static const int value = v[0];
}

All of them build individually, though when I throw in my test,

cout << typeid(something2<"abcd">::value).name() << endl;

I get

'something2' : invalid expression as a template argument for 'v'
'something2' : use of class template requires template argument list

Is this not feasible or am I misunderstanding something?

14.1 lists the acceptable types of non-type template arguments:

— integral or enumeration type,
— pointer to object or pointer to function,
— lvalue reference to object or lvalue reference to function,
— pointer to member,

Arrays don't fit under any of these categories.

14.3.2/1 lists categories of what's permitted as template arguments and 14.3.2/2 goes on to say:

Note: A string literal (2.14.5) does not satisfy the requirements of any of these categories and thus is not an acceptable template-argument.

Therefore you cannot do what you're trying to do.

you cannot, from the standard.

14.3.2.1:

A template-argument for a non-type, non-template template-parameter shall be one of:

  • an integral constant-expression of integral or enumeration type; or
  • the name of a non-type template-parameter; or
  • the address of an object or function with external linkage, including function templates >and function template-ids but excluding non-static class members, expressed as & id->expression where the & is optional if the name refers to a function or array, or if the >corresponding template-parameter is a reference; or
  • a pointer to member expressed as described in 5.3.1 .

There is a way to get close to what you are wanting. Possibly this will work for you, although it adds an extra level of code to be maintained.

It requires defining const char arrays with external linkage, then using the names of those arrays to instantiate classes from the templates. Of course in real use this code would be separated into various .h and .cpp files.

extern const char a[] = "a";
extern const char b[] = "b";
extern const char ab[] = "ab";
extern const char abc[] = "abc";

template <const char * const  T> class Test
{
public:
    Test() {str = typename T;};
private:
    const char * str;
};


SomeFunction()
{
    Test<a> A;
    Test<b> B;
    Test<ab> AB;
    Test<abc> ABC;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM