I want to make integral constant from char* and "kernel32.dll", but failed always. The following are my failed attempts, anyone can show me the correct usage?
error 1: cout << std::integral_constant<const char*, "kernel32.dll">::value << endl;
error 2: cout << std::integral_constant<char*, "kernel32.dll">::value << endl;
error 3: cout << std::integral_constant<char[], "kernel32.dll">::value << endl;
error 4: cout << cout << std::integral_constant<char*, static_cast<char*>("kernel32.dll")>::value << endl;
the above 4 statements have the same error info.:
Console.cpp(181): error C2762: 'std::integral_constant' : invalid expression as a template argument for '_Val'
1> D:\Programfiles\Visual Studio 2013\VC\include\xtr1common(35) : see declaration of 'std::integral_constant'
1>Console.cpp(181): error C2955: 'std::integral_constant' : use of class template requires template argument list
1> D:\Programfiles\Visual Studio 2013\VC\include\xtr1common(35) : see declaration of 'std::integral_constant'
1>Console.cpp(181): warning C4552: '<<' : operator has no effect; expected operator with side-effect
Update:
std::integral_constant<std::string, "abc">::value won't compile either.
end update
Here is my scenario, I make a simple demo to demonstrate my purpose:
#include <iostream>
#include <type_traits>
template< typename R, typename C, typename... Args>
class delegate
{
public:
template<R(C::*F)(Args...), typename ... Ts>
struct adapter
{
static R invoke_no_fwd(Args... args)
{
C t((Ts::value)...);
return (t.*F)(args...);
}
};
};
class Class
{
public:
Class(const char* psz) {
std::cout << psz << std::endl;
}
void print(int v)
{
std::cout << "Class: " << v << std::endl;
}
};
int main()
{
typedef void(*function_t)(int);
function_t ptrFunc = delegate<void, Class, int>::adapter<&Class::print, std::integral_constant<char*, "money"> >::invoke_no_fwd;
auto type = delegate<void, Class, int>::adapter<&Class::print, std::integral_constant<int, 42>>::invoke_no_fwd;
ptrFunc(-42); // 0
type(0); // 42
return 0;
}
The template parameter type in your code, currently instantiated with std::integral_constant<>, is used only to access ::value static member, so you can replace it with any other type defining value member, just like shown below:
#include <iostream>
template <typename T>
void print()
{
std::cout << (T::value) << std::endl;
}
struct X
{
static const char* value;
};
const char* X::value = "ABC";
int main()
{
print<X>();
}
That is, just put X in place of std::integral_constant<>.
function_t ptrFunc
= delegate<void, Class, int>
::adapter<&Class::print, X /*here!*/>
::invoke_no_fwd;
Live demo link.
UPDATE 1
If you want to specify the string's content inline, within template instantiation, the below code will do the trick:
template <char... Chars>
struct MyString
{
static constexpr char value[] = { Chars..., '\0' };
};
template <char... Chars>
constexpr char MyString<Chars...>::value[];
// MyString<'A', 'B', 'C'>::value is same as const char[4] = { "ABC" };
function_t ptrFunc
= delegate<void, Class, int>
::adapter<&Class::print, MyString<'A', 'B', 'C'>>
::invoke_no_fwd;
Another live demo link.
UPDATE 2
If you are tired of typing MyString<'k','e','r','n','e','l','3','2','.','d','l','l'> you can instead expand a raw string like "kernel32.dll" into comma-separated characters list compliant with MyString<char...> template, using below macro (that for simplicity is limited to 32-character-long strings):
#include <iostream>
#define STR_1(S,I) (I < sizeof(S) ? S[I] : '\0')
#define STR_2(S,I) STR_1(S,I), STR_1(S,I+1)
#define STR_4(S,I) STR_2(S,I), STR_2(S,I+2)
#define STR_8(S,I) STR_4(S,I), STR_4(S,I+4)
#define STR_16(S,I) STR_8(S,I), STR_8(S,I+8)
#define STR_32(S,I) STR_16(S,I), STR_16(S,I+16)
#define STR(S) STR_32(S,0)
template <char... Chars>
struct MyString
{
static constexpr char value[] = { Chars..., '\0' };
};
template <char... Chars>
constexpr char MyString<Chars...>::value[];
int main()
{
std::cout << MyString<STR("kernel32.dll")>::value << std::endl;
}
Yet another live demo link
You may declare a static const char* and use it in std::integral_constant, something like:
static constexpr const char money[] = "money";
int main()
{
typedef void(*function_t)(int);
function_t ptrFunc =
delegate<void, Class, int>
::adapter<
&Class::print,
std::integral_constant<const char*, money> >::invoke_no_fwd;
auto type = delegate<void, Class, int>::
adapter<&Class::print, std::integral_constant<const char*, money>>::invoke_no_fwd;
ptrFunc(-42); // 0
type(0); // 42
return 0;
}
Live example
You may use something like in Aligning static string literals to allow to write the literal string in std::integral_constant with a Macro.
Related
This question already has answers here:
Passing a string literal as a type argument to a class template
(17 answers)
Closed 6 years ago.
I'm trying to find a comfortable way to pass string literals as template arguments. I'm not caring about supporting the widest possible number of compilers, I'm using the latest version of g++ with --std=c++0x.
I've tried a lot of possible solutions but all have disappointed me. I'm sort of giving up, but first I'd like to know why a couple of them failed.
Here they are:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
char const *operator () () const {
return m_sz;
}
};
template<class _rstr>
string const Get() {
return _rstr();
}
int main() {
cout << Get<String("hello")>() << endl;
return 0;
}
And:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
int main() {
String constexpr str = "hello";
cout << Get<str>() << endl;
return 0;
}
The goal was to find a comfortable way to pass a string literal to the useless Get function, which returns its template argument as an std::string object.
EDIT: sorry, maybe my main question isn't clear. My question is: why do those two snippets fail?
You can't use string literals as a template argument, for the
simple reason that it's unspecified whether two instances of a
literal with the same text are the same object or not. In other
words, given:
template <char const* str>
class TC {};
TC< "xyz" > v1;
TC< "xyz" > v2;
It would be unspecified whether v1 and v2 had the same type
or not.
You can use char const[] variables as template arguments,
however, since they have a defined address:
template <char const* str>
class TC {};
extern char const xyz[] = "xyz";
TC< xyz > v1;
TC< xyz > v2;
In this case, v1 and v2 are guaranteed to have the same
type.
EDIT:
I think C++11 removes the need for the extern on the
definition of the string, at least if the string and the
instantiation are all in the same translation unit. I'm not
sure, however; the one time I did something like this, I didn't
have access to C++11.
I know the post is old but I haven't found any solution for this problem here, and maybe someone would be interested in my workaround:
template <int N>
constexpr int string_literal_length(const char (&str)[N]) {
return N - 1;
}
template <int PassedLength, int CountedLength, char... Characters>
struct string_literal {
static_assert(PassedLength == CountedLength, "Passed to STRING_LITERAL length does not match the length of string...");
};
#define STRING_LITERAL(N, str) string_literal<N, string_literal_length(str), STRING_LITERAL_##N(str)>
// ... as long as we need it ...
#define STRING_LITERAL_128(str) STRING_LITERAL_127(str), str[127]
#define STRING_LITERAL_127(str) STRING_LITERAL_126(str), str[126]
#define STRING_LITERAL_126(str) STRING_LITERAL_125(str), str[125]
#define STRING_LITERAL_125(str) STRING_LITERAL_124(str), str[124]
// ...
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), str[4]
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), str[3]
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), str[2]
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), str[1]
#define STRING_LITERAL_1(str) str[0]
Now usage:
template <class SLiteral>
struct usage_of_string_literal {
};
int main() {
usage_of_string_literal<STRING_LITERAL(12, "123456789012")> uosl;
}
Unfortunately one have to provide the length of the string to get it work but it's still more comfortable solution than plain variadic arg template of chars, and the length is verified by the static_assert so the compiler can help to pick appropriate value...
Edit
One more template magic. This one is making use of short-circuit to get rid of the string size from STRING_LITERAL declaration (c++17):
#include <type_traits>
#include <utility>
#define MAX_STRING_LITERAL_LENGTH 11
#define STRING_LITERAL(str) string_literal<char_pack<STRING_LITERAL_11(str)>>::s
#define STRING_LITERAL_11(str) STRING_LITERAL_10(str), ((TERMINATED_10(str))?(str[10]):('\0'))
#define STRING_LITERAL_10(str) STRING_LITERAL_9(str), ((TERMINATED_9(str))?(str[9]):('\0'))
#define STRING_LITERAL_9(str) STRING_LITERAL_8(str), ((TERMINATED_8(str))?(str[8]):('\0'))
#define STRING_LITERAL_8(str) STRING_LITERAL_7(str), ((TERMINATED_7(str))?(str[7]):('\0'))
#define STRING_LITERAL_7(str) STRING_LITERAL_6(str), ((TERMINATED_6(str))?(str[6]):('\0'))
#define STRING_LITERAL_6(str) STRING_LITERAL_5(str), ((TERMINATED_5(str))?(str[5]):('\0'))
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), ((TERMINATED_4(str))?(str[4]):('\0'))
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), ((TERMINATED_3(str))?(str[3]):('\0'))
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), ((TERMINATED_2(str))?(str[2]):('\0'))
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), ((TERMINATED_1(str))?(str[1]):('\0'))
#define STRING_LITERAL_1(str) str[0]
#define TERMINATED_10(str) TERMINATED_9(str) && str[9]
#define TERMINATED_9(str) TERMINATED_8(str) && str[8]
#define TERMINATED_8(str) TERMINATED_7(str) && str[7]
#define TERMINATED_7(str) TERMINATED_6(str) && str[6]
#define TERMINATED_6(str) TERMINATED_5(str) && str[5]
#define TERMINATED_5(str) TERMINATED_4(str) && str[4]
#define TERMINATED_4(str) TERMINATED_3(str) && str[3]
#define TERMINATED_3(str) TERMINATED_2(str) && str[2]
#define TERMINATED_2(str) TERMINATED_1(str) && str[1]
#define TERMINATED_1(str) str[0]
template <char... Cs>
struct char_pack {
static constexpr char const arr[sizeof...(Cs) + 1] = {Cs..., 0};
static constexpr std::size_t non_zero_count = (((Cs != 0)?1:0) + ...);
static_assert(non_zero_count < MAX_STRING_LITERAL_LENGTH, "You need to create more macros");
};
template <char... Cs>
constexpr char const char_pack<Cs...>::arr[sizeof...(Cs) + 1];
template <char... Cs>
constexpr std::size_t char_pack<Cs...>::non_zero_count;
template <class CP, class = void, class = std::make_index_sequence<CP::non_zero_count>>
struct string_literal;
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>> {
static constexpr char const s[sizeof...(Cs) + 1] = {Cs..., '\0'};
};
template <char... Cs, std::size_t... Is>
constexpr char const string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>>::s[sizeof...(Cs) + 1];
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<!(Cs && ...)>, std::index_sequence<Is...>>: string_literal<char_pack<char_pack<Cs...>::arr[Is]...>> { };
template <const char *>
struct foo {};
int main() {
foo<STRING_LITERAL("abcdefghij")> f;
static_cast<void>(f);
}
[live demo]
You can "simulate" strings with C++11 variadic templates:
template<char... CHARS>
struct string
{
operator const std::string&()
{
static const std::string str{ { CHARS... } };
return str;
}
}
int main()
{
using my_string = string<'h','e','l','l','o',' ','w','o','r','l','d','!','!','!'>;
std::cout << my_string() << std::endl;
}
This prints:
hello world!!!
re: your OP: I'd like to know why a couple of them failed.
The comment by #NatanReed is correct:
Your first snippet fails because Get needs a TYPE and is given an object.
Your second snippet fails because it is illegal to define a template argument as reference to an object.
until C++2003, that is. Then reference to an object became legal.
Template arguments must be constants from a limited set of types.
See: ISO/IEC 14882-2003 §14.1: Template parameters
See: ISO/IEC 14882-2003 §14.3.2: Template non-type arguments
And even then, the String constexpr str = "hello"; must have external linkage. So putting it on the stack inside of main() is not going to work.
Give this a try:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
extern String constexpr globally_visible_str = "hello";
int main() {
cout << Get<globally_visible_str>() << endl;
return 0;
}
Consider a minimal example
#include <iostream>
template<typename T>
struct foo
{
// won't compile. how to change?
static constexpr char sep[3] = std::is_integral<T>::value ? ". " : ", ";
// many other things ...
};
int main()
{
std::cout << foo<int>::sep << std::endl; // prints .
std::cout << foo<double>::sep << std::endl; // prints ,
}
What I want to achieve is:
if T has an integral type, then sep is initialized to .
otherwise, sep is initialized to ,
However, the compiler won't allow this, saying
error: array must be initialized with a brace-enclosed initializer
It looks like something must be done in compile time. But I am not sure how to do it.
My question is: is there anything I can do to achieve this end?
Note: Minimal change is most welcome. There ought to be many other things in foo. Another consideration is that I want to keep everything about foo in header and to leave nothing in source file, if possible.
Thank you very much.
C-arrays are not copyable, so you have to work-around that
Do the check for each character:
constexpr char sep[3] = { std::is_integral<T>::value ? '.' : ',', ' ', '\0' };
Don't use array but pointer (so you loose size):
constexpr const char* sep = std::is_integral<T>::value ? ". " : ", ";
Use std::array:
constexpr std::array<char, 3> sep = std::is_integral<T>::value
? std::array<char, 3>{{'.', ' ', 0}}
: std::array<char, 3>{{',', ' ', 0}};
Use reference to array:
constexpr char dot_sep[3] = std::is_integral<T>::value ? ". " : ", ";
constexpr char comma_sep[3] = std::is_integral<T>::value ? ". " : ", ";
constexpr const char (&sep)[3] = std::is_integral<T>::value ? dot_sep : comma_sep;
and provide definition of dot_sep/comma_sep which are ODR-used.
The best way is to use base class with specialization, and put sep in the base class:
template <bool IsIntegral>
struct foo_base;
template<>
struct foo_base<true>
{
static constexpr char sep[3] = ". ";
};
template<>
struct foo_base<false>
{
static constexpr char sep[4] = ", ";
};
template<typename T>
struct foo : foo_base<std::is_integral_v<T>>
{
// many other things ...
};
But if you don't want others to access the base, you can use private inheritance:
template<typename T>
struct foo : private foo_base<std::is_integral_v<T>>
{
using foo_base<std::is_integral_v<T>>::sep;
// many other things ...
};
Edit
The advantage of this solution over using a std::array<char, 3>, is that this solution plays nicely with functions that accept a reference to C arrays of char. Neither storing const char* nor std::array<char, 3> have this capability.
For example, if you have functions like:
template <std::size_t I>
constexpr int count_nuls(const char (&x)[I])
{
// Can't use std::count, since it is not constexpr
unsigned count = 0;
for (auto ch: x)
if (ch == '\0')
++count;
return count;
}
This function can't be used with std::array, or with a const char *. If there are many functions like that, one may not want to upgrade all of them to std::array. For example, this function works perfectly in:
static constexpr unsigned nuls = count_nuls(foo<double>::sep);
But won't work (without further modification) with std::array<char, 3>.
I've been able to progress further with my variadic template from my previous question. I've now got a new question. In this code example:
#include <iostream>
#include <cstddef>
constexpr std::uint32_t Flag0 = 0x0001;
constexpr std::uint32_t Flag1 = 0x0002;
constexpr std::uint32_t Flag2 = 0x0004;
constexpr std::uint32_t FlagAll = 0xFFFF;
template<std::uint32_t...Cs>
struct flags_tag {constexpr flags_tag(){}; };
template<std::uint32_t...Cs>
struct make_flags{ using type=flags_tag<Cs...>; };
template<std::uint32_t...Cs>
using make_flags_t=typename make_flags<Cs...>::type;
template<std::uint32_t value>
class pValue_t
{
template<std::uint32_t StateMask, class flags>
friend class Compound;
};
template<> class pValue_t<Flag0>
{
public:
pValue_t() :
m_pValue0(reinterpret_cast<void*>(0xFFFFFFFF))
{}
protected:
void* m_pValue0;
};
template<> class pValue_t<Flag1>
{
public:
pValue_t() :
m_pValue1(reinterpret_cast<void*>(0xDEADBEEF))
{}
protected:
void* m_pValue1;
};
template<> class pValue_t<Flag2>
{
public:
pValue_t() :
m_pValue2(reinterpret_cast<void*>(0xCAFEBABE))
{}
protected:
void* m_pValue2;
};
template<std::uint32_t StateMask, class flags>
class Compound;
template<std::uint32_t StateMask, std::uint32_t...Cs>
class Compound< StateMask, flags_tag<Cs...> >:
public pValue_t<Cs>...
{
public:
void print()
{
if (IsStateValid(Flag0))
{
std::cout << this->m_pValue0 << '\n';
}
if ((StateMask & Flag1) == Flag1)
{
std::cout << this->m_pValue1 << '\n';
}
// *** THIS IS THE PROBLEM STATEMENT ***
if (IsStateValid(Flag2))
{
std::cout << this->m_pValue2 << '\n';
}
}
static bool IsStateValid(std::uint32_t stateMask)
{ return ((StateMask & stateMask) == stateMask); }
uint32_t m_stateMask;
};
using my_type = Compound< Flag0 | Flag1, make_flags_t<Flag0, Flag1>>;
int main() {
my_type test;
test.print();
}
the print function contains a reference to m_pValue2, which is valid when the StateMask contains Flag2.
Now, the compiler is warning that it cannot find m_pValue2. I would like for the compiler to remove the chunk of code that references m_pValue2 when the StateMask (known at compile time) does not contain Flag2 (when IsStateValid() is false).
The exact error is as follows:
main.cpp: In instantiation of 'void Compound<StateMask, flags_tag<Cs ...> >::print() [with unsigned int StateMask = 3u; unsigned int ...Cs = {1u, 2u}]':
main.cpp:95:18: required from here
main.cpp:80:27: error: 'class Compound<3u, flags_tag<1u, 2u> >' has no member named 'm_pValue2'
std::cout << this->m_pValue2 << '\n';
I'm hoping this is possible. In other template programming, I've used IsStateValid() to compile out code segments that don't match the StateMask. I've never tried to compile away a possibly missing member variable, however.
Does anyone have any ideas?
Why it doesn't work
All branches in a function template will be compiled regardless of type. It doesn't matter that IsStateValid(Flag2) would be false at compile time, the body of that if must be valid code. As there is no this->m_pValue2 in that case, this is a hard error.
What can you do to fix it
You need to forward each print flag function to a function template that will either print the value (if it exists) or do nothing (if it doesn't). We can use function overloading to help here, and ensure that the entire function will not be instantiated if there is no such flag. For example:
void print()
{
printImpl<Flag0>();
printImpl<Flag1>();
printImpl<Flag2>();
}
template <uint32_t F>
void printImpl() {
printImpl<F>(std::is_base_of<pValue_t<F>, Compound>{});
}
template <uint32_t F>
void printImpl(std::true_type ) {
// we DO have this flag
pValue_t<F>::print();
}
template <uint32_t F>
void printImpl(std::false_type ) {
// we do NOT have this flag
// so do nothing
}
All you need to do at this point is add the appropriate print()s. e.g.:
template<> class pValue_t<Flag2>
{
public:
pValue_t() :
m_pValue2(reinterpret_cast<void*>(0xCAFEBABE))
{}
void print() {
std::cout << m_pValue2 << '\n';
}
protected:
void* m_pValue2;
};
I got this to work (working example), but it seems very hacky. It shows that it's possible - hopefully a more experienced person than I can clean it up.
The idea is to make IsStataValid a constexpr and separate the code in question out into another function, which has two variants. The variant that gets instantiated depends on the compile-time flag:
static constexpr bool IsStateValid(std::uint32_t stateMask)
{ return ((StateMask & stateMask) == stateMask); }
template <typename A = void,
typename T = typename std::enable_if<IsStateValid(Flag2), A>::type>
void blub(int x=0) {
std::cout << this->m_pValue2 << '\n';
}
template <typename A = void,
typename T = typename std::enable_if<!IsStateValid(Flag2), A>::type>
void blub(long x=0) {
}
Then instead of the if statement in print() you call the helper function:
blub();
typename A is a dummy parameter to make the enable_if dependent on a template parameter so SFINAE can kick in. The blubs take a first parameter of a different type so the compiler doesn't complain about it not being able to be overloaded.
This question already has answers here:
Passing a string literal as a type argument to a class template
(17 answers)
Closed 6 years ago.
I'm trying to find a comfortable way to pass string literals as template arguments. I'm not caring about supporting the widest possible number of compilers, I'm using the latest version of g++ with --std=c++0x.
I've tried a lot of possible solutions but all have disappointed me. I'm sort of giving up, but first I'd like to know why a couple of them failed.
Here they are:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
char const *operator () () const {
return m_sz;
}
};
template<class _rstr>
string const Get() {
return _rstr();
}
int main() {
cout << Get<String("hello")>() << endl;
return 0;
}
And:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
int main() {
String constexpr str = "hello";
cout << Get<str>() << endl;
return 0;
}
The goal was to find a comfortable way to pass a string literal to the useless Get function, which returns its template argument as an std::string object.
EDIT: sorry, maybe my main question isn't clear. My question is: why do those two snippets fail?
You can't use string literals as a template argument, for the
simple reason that it's unspecified whether two instances of a
literal with the same text are the same object or not. In other
words, given:
template <char const* str>
class TC {};
TC< "xyz" > v1;
TC< "xyz" > v2;
It would be unspecified whether v1 and v2 had the same type
or not.
You can use char const[] variables as template arguments,
however, since they have a defined address:
template <char const* str>
class TC {};
extern char const xyz[] = "xyz";
TC< xyz > v1;
TC< xyz > v2;
In this case, v1 and v2 are guaranteed to have the same
type.
EDIT:
I think C++11 removes the need for the extern on the
definition of the string, at least if the string and the
instantiation are all in the same translation unit. I'm not
sure, however; the one time I did something like this, I didn't
have access to C++11.
I know the post is old but I haven't found any solution for this problem here, and maybe someone would be interested in my workaround:
template <int N>
constexpr int string_literal_length(const char (&str)[N]) {
return N - 1;
}
template <int PassedLength, int CountedLength, char... Characters>
struct string_literal {
static_assert(PassedLength == CountedLength, "Passed to STRING_LITERAL length does not match the length of string...");
};
#define STRING_LITERAL(N, str) string_literal<N, string_literal_length(str), STRING_LITERAL_##N(str)>
// ... as long as we need it ...
#define STRING_LITERAL_128(str) STRING_LITERAL_127(str), str[127]
#define STRING_LITERAL_127(str) STRING_LITERAL_126(str), str[126]
#define STRING_LITERAL_126(str) STRING_LITERAL_125(str), str[125]
#define STRING_LITERAL_125(str) STRING_LITERAL_124(str), str[124]
// ...
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), str[4]
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), str[3]
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), str[2]
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), str[1]
#define STRING_LITERAL_1(str) str[0]
Now usage:
template <class SLiteral>
struct usage_of_string_literal {
};
int main() {
usage_of_string_literal<STRING_LITERAL(12, "123456789012")> uosl;
}
Unfortunately one have to provide the length of the string to get it work but it's still more comfortable solution than plain variadic arg template of chars, and the length is verified by the static_assert so the compiler can help to pick appropriate value...
Edit
One more template magic. This one is making use of short-circuit to get rid of the string size from STRING_LITERAL declaration (c++17):
#include <type_traits>
#include <utility>
#define MAX_STRING_LITERAL_LENGTH 11
#define STRING_LITERAL(str) string_literal<char_pack<STRING_LITERAL_11(str)>>::s
#define STRING_LITERAL_11(str) STRING_LITERAL_10(str), ((TERMINATED_10(str))?(str[10]):('\0'))
#define STRING_LITERAL_10(str) STRING_LITERAL_9(str), ((TERMINATED_9(str))?(str[9]):('\0'))
#define STRING_LITERAL_9(str) STRING_LITERAL_8(str), ((TERMINATED_8(str))?(str[8]):('\0'))
#define STRING_LITERAL_8(str) STRING_LITERAL_7(str), ((TERMINATED_7(str))?(str[7]):('\0'))
#define STRING_LITERAL_7(str) STRING_LITERAL_6(str), ((TERMINATED_6(str))?(str[6]):('\0'))
#define STRING_LITERAL_6(str) STRING_LITERAL_5(str), ((TERMINATED_5(str))?(str[5]):('\0'))
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), ((TERMINATED_4(str))?(str[4]):('\0'))
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), ((TERMINATED_3(str))?(str[3]):('\0'))
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), ((TERMINATED_2(str))?(str[2]):('\0'))
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), ((TERMINATED_1(str))?(str[1]):('\0'))
#define STRING_LITERAL_1(str) str[0]
#define TERMINATED_10(str) TERMINATED_9(str) && str[9]
#define TERMINATED_9(str) TERMINATED_8(str) && str[8]
#define TERMINATED_8(str) TERMINATED_7(str) && str[7]
#define TERMINATED_7(str) TERMINATED_6(str) && str[6]
#define TERMINATED_6(str) TERMINATED_5(str) && str[5]
#define TERMINATED_5(str) TERMINATED_4(str) && str[4]
#define TERMINATED_4(str) TERMINATED_3(str) && str[3]
#define TERMINATED_3(str) TERMINATED_2(str) && str[2]
#define TERMINATED_2(str) TERMINATED_1(str) && str[1]
#define TERMINATED_1(str) str[0]
template <char... Cs>
struct char_pack {
static constexpr char const arr[sizeof...(Cs) + 1] = {Cs..., 0};
static constexpr std::size_t non_zero_count = (((Cs != 0)?1:0) + ...);
static_assert(non_zero_count < MAX_STRING_LITERAL_LENGTH, "You need to create more macros");
};
template <char... Cs>
constexpr char const char_pack<Cs...>::arr[sizeof...(Cs) + 1];
template <char... Cs>
constexpr std::size_t char_pack<Cs...>::non_zero_count;
template <class CP, class = void, class = std::make_index_sequence<CP::non_zero_count>>
struct string_literal;
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>> {
static constexpr char const s[sizeof...(Cs) + 1] = {Cs..., '\0'};
};
template <char... Cs, std::size_t... Is>
constexpr char const string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>>::s[sizeof...(Cs) + 1];
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<!(Cs && ...)>, std::index_sequence<Is...>>: string_literal<char_pack<char_pack<Cs...>::arr[Is]...>> { };
template <const char *>
struct foo {};
int main() {
foo<STRING_LITERAL("abcdefghij")> f;
static_cast<void>(f);
}
[live demo]
You can "simulate" strings with C++11 variadic templates:
template<char... CHARS>
struct string
{
operator const std::string&()
{
static const std::string str{ { CHARS... } };
return str;
}
}
int main()
{
using my_string = string<'h','e','l','l','o',' ','w','o','r','l','d','!','!','!'>;
std::cout << my_string() << std::endl;
}
This prints:
hello world!!!
re: your OP: I'd like to know why a couple of them failed.
The comment by #NatanReed is correct:
Your first snippet fails because Get needs a TYPE and is given an object.
Your second snippet fails because it is illegal to define a template argument as reference to an object.
until C++2003, that is. Then reference to an object became legal.
Template arguments must be constants from a limited set of types.
See: ISO/IEC 14882-2003 §14.1: Template parameters
See: ISO/IEC 14882-2003 §14.3.2: Template non-type arguments
And even then, the String constexpr str = "hello"; must have external linkage. So putting it on the stack inside of main() is not going to work.
Give this a try:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
extern String constexpr globally_visible_str = "hello";
int main() {
cout << Get<globally_visible_str>() << endl;
return 0;
}
I want to declare a class template in which one of the template parameters takes a string literal, e.g. my_class<"string">.
Can anyone give me some compilable code which declares a simple class template as described?
Note: The previous wording of this question was rather ambiguous as to what the asker was actually trying to accomplish, and should probably have been closed as insufficiently clear. However, since then this question became multiple times referred-to as the canonical ‘string literal type parameter’ question. As such, it has been re-worded to agree with that premise.
You can have a const char* non-type template parameter, and pass it a const char[] variable with static linkage, which is not all that far from passing a string literal directly.
#include <iostream>
template<const char *str>
struct cts {
void p() {std::cout << str;}
};
static const char teststr[] = "Hello world!";
int main() {
cts<teststr> o;
o.p();
}
http://coliru.stacked-crooked.com/a/64cd254136dd0272
Further from Neil's answer: one way to using strings with templates as you want is to define a traits class and define the string as a trait of the type.
#include <iostream>
template <class T>
struct MyTypeTraits
{
static const char* name;
};
template <class T>
const char* MyTypeTraits<T>::name = "Hello";
template <>
struct MyTypeTraits<int>
{
static const char* name;
};
const char* MyTypeTraits<int>::name = "Hello int";
template <class T>
class MyTemplateClass
{
public:
void print() {
std::cout << "My name is: " << MyTypeTraits<T>::name << std::endl;
}
};
int main()
{
MyTemplateClass<int>().print();
MyTemplateClass<char>().print();
}
prints
My name is: Hello int
My name is: Hello
C++20 fixed_string + "Class Types in Non-Type Template Parameters"
Apparently, a proposal for this was first accepted, but then removed: "String literals as non-type template parameters"
The removal was partly because it was deemed to be easy enough to do with another proposal that was accepted: "Class Types in Non-Type Template Parameters".
The accepted proposal contains an example with the following syntax:
template <std::basic_fixed_string Str>
struct A {};
using hello_A = A<"hello">;
I'll try to update this with an example that actually tells me anything once I see a compiler that supports it.
A Redditor has also shown that the following compiles on GCC master, provided you define your own version of basic_fixed_string which was not in the standard library yet: https://godbolt.org/z/L0J2K2
template<unsigned N>
struct FixedString {
char buf[N + 1]{};
constexpr FixedString(char const* s) {
for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
}
constexpr operator char const*() const { return buf; }
};
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;
template<FixedString T>
class Foo {
static constexpr char const* Name = T;
public:
void hello() const;
};
int main() {
Foo<"Hello!"> foo;
foo.hello();
}
g++ -std=c++2a 9.2.1 from the Ubuntu PPA fails to compile that with:
/tmp/ccZPAqRi.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `_ZNK3FooIXtl11FixedStringILj6EEtlA7_cLc72ELc101ELc108ELc108ELc111ELc33EEEEE5helloEv'
collect2: error: ld returned 1 exit status
Bibliography: https://botondballo.wordpress.com/2018/03/28/trip-report-c-standards-meeting-in-jacksonville-march-2018/
Finally, EWG decided to pull the previously-approved proposal to allow string literals in non-type template parameters, because the more general facility to allow class types in non-type template parameters (which was just approved) is a good enough replacement. (This is a change from the last meeting, when it seemed like we would want both.) The main difference is that you now have to wrap your character array into a struct (think fixed_string or similar), and use that as your template parameter type. (The user-defined literal part of P0424 is still going forward, with a corresponding adjustment to the allowed template parameter types.)
This will be especially cool with the C++17 if constexpr: if / else at compile time in C++?
This kind of feature appears to be in line with the awesome "constexpr everything" proposals that went into C++20, such as: Is it possible to use std::string in a constexpr?
Sorry, C++ does not currently support the use of string literals (or real literals) as template parameters.
But re-reading your question, is that what you are asking? You cannot say:
foo <"bar"> x;
but you can say
template <typename T>
struct foo {
foo( T t ) {}
};
foo <const char *> f( "bar" );
This is a solution with MPLLIBS to pass a strings as template arguments ( C++11 ).
#include <iostream>
#include <mpllibs/metaparse/string.hpp> // https://github.com/sabel83/mpllibs
#include <boost/mpl/string.hpp>
// -std=c++11
template<class a_mpl_string>
struct A
{
static const char* string;
};
template<class a_mpl_string>
const char* A< a_mpl_string >
::string { boost::mpl::c_str< a_mpl_string >::value }; // boost compatible
typedef A< MPLLIBS_STRING ( "any string as template argument" ) > a_string_type;
int main ( int argc, char **argv )
{
std::cout << a_string_type{}.string << std::endl;
return 0;
}
prints:
any string as template argument
The lib on github: https://github.com/sabel83/mpllibs
inline const wchar_t *GetTheStringYouWant() { return L"The String You Want"; }
template <const wchar_t *GetLiteralFunc(void)>
class MyType
{
void test()
{
std::cout << GetLiteralFunc;
}
}
int main()
{
MyType<GetTheStringYouWant>.test();
}
Try it with pasing the address of a function as the template argument.
EDIT: ok the title of your question seems to be misleading
"I want a class which takes two parameters in its constructor. The first can be either an int, double or float, so , and the second is always a string literal "my string", so I guess const char * const."
It looks like you're trying to achieve:
template<typename T>
class Foo
{
public:
Foo(T t, const char* s) : first(t), second(s)
{
// do something
}
private:
T first;
const char* second;
};
This would work for any type, for the first parameter: int, float, double, whatever.
Now if you really want to restrict the type of the first parameter to be only int, float or double; you can come up with something more elaborate like
template<typename T>
struct RestrictType;
template<>
struct RestrictType<int>
{
typedef int Type;
};
template<>
struct RestrictType<float>
{
typedef float Type;
};
template<>
struct RestrictType<double>
{
typedef double Type;
};
template<typename T>
class Foo
{
typedef typename RestrictType<T>::Type FirstType;
public:
Foo(FirstType t, const char* s) : first(t), second(s)
{
// do something
}
private:
FirstType first;
const char* second;
};
int main()
{
Foo<int> f1(0, "can");
Foo<float> f2(1, "i");
Foo<double> f3(1, "have");
//Foo<char> f4(0, "a pony?");
}
If you remove the comment on the last line, you'll effectively get a compiler error.
String literals are not allowed by C++2003
ISO/IEC 14882-2003 §14.1:
14.1 Template parameters
A non-type template-parameter shall have one of the following (optionallycv-qualified) types:
— integral or enumeration type,
— pointer to object or pointer to function,
— reference to object or reference to function,
— pointer to member.
ISO/IEC 14882-2003 §14.3.2:
14.3.2 Template non-type arguments
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.
[Note:A string literal (2.13.4) does not satisfy the requirements of any of these categories and thus is not an acceptable template-argument.
[Example:
template<class T, char* p> class X {
//...
X();
X(const char* q) { /* ... */ }
};
X<int,"Studebaker"> x1; //error: string literal as template-argument
char p[] = "Vivisectionist";
X<int,p> x2; //OK
—end example] —end note]
And it looks like it's not going to change in the upcoming C++0X, see the current draft 14.4.2 Template non-type arguments.
Based on your comments under Niel's answer, another possibility is the following:
#include <iostream>
static const char* eventNames[] = { "event_A", "event_B" };
enum EventId {
event_A = 0,
event_B
};
template <int EventId>
class Event
{
public:
Event() {
name_ = eventNames[EventId];
}
void print() {
std::cout << name_ << std::endl;
}
private:
const char* name_;
};
int main()
{
Event<event_A>().print();
Event<event_B>().print();
}
prints
event_A
event_B
You cannot pass a string literal directly as a template parameter.
But you can get close:
template<class MyString = typestring_is("Hello!")>
void MyPrint() {
puts( MyString::data() );
}
...
// or:
MyPrint<typestring_is("another text")>();
...
All you need is a small header file from here.
Alternatives:
Define a global char const * and pass it to the template as pointer. (here)
Drawback: Requires additional code outside of the template argument list. It is not suitable, if you need to specify the string literal "inline".
Use a non-standard language extension. (here)
Drawback: Not guaranteed to work with all compilers.
Use BOOST_METAPARSE_STRING. (here)
Drawback: Your code will depend on the Boost library.
Use a variadic template parameter pack of char, e.g. str_t<'T','e','s','t'>.
This is what the above solution does for you behind the scenes.
Use proxy static constexpr const char type_name_str[] = {"type name"}; for passing string as template parameter. Defining string using [] is important.
#include <iostream>
template<typename T, const char* const t_name>
struct TypeName
{
public:
static constexpr const char* Name()
{
return t_name;
};
};
static constexpr const char type_name_str[] = {"type name"};
int main()
{
std::cout<<TypeName<float, type_name_str>::Name();
return 0;
}
I want a class which takes two parameters in its constructor. The first can be either an int, double or float, so , and the second is always a string literal "my string"
template<typename T>
class demo
{
T data;
std::string s;
public:
demo(T d,std::string x="my string"):data(d),s(x) //Your constructor
{
}
};
I am not sure but is this something what you want?
Maybe not what the OP is asking, but if you use boost, you can create a macro like this for example:
#define C_STR(str_) boost::mpl::c_str< BOOST_METAPARSE_STRING(str_) >::value
Then use as follows:
template<const char* str>
structe testit{
};
testit<C_STR("hello")> ti;
template <char... elements>
struct KSym /* : optional_common_base */ {
// We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
const char z[sizeof...(elements) + 1] = { elements..., '\0' };
// We can have properties, we don't need anything to be constexpr for Rs
};
template <typename T, T... chars>
auto&& operator""_ksym() {
static KSym<chars...> kSym; // Construct the unique singleton (lazily on demand)
return kSym;
}
static auto ksym_example1 = "a unique string symbol1\n"_ksym.z;
static auto ksym_example2 = "a unique string symbol2\n"_ksym.z;
auto dont_care = []() {
::OutputDebugString(ksym_example1);
::OutputDebugString("a unique string symbol2\n"_ksym.z);
assert("a unique string symbol1\n"_ksym.z == ksym_example1);
assert("a unique string symbol2\n"_ksym.z == ksym_example2);
return true;
}();
The above is working for me in production using Clang 11 on Windows.
(edited) I now use exactly this in clang on Windows:
// P0424R1: http://www.open-std.org/jtc1/SC22/wg21/docs/papers/2017/p0424r1.pdf
template <char... chars_ta> struct KSymT;
template <typename T, T... chars_ta> // std::move(KSymT<chars_ta...>::s);
auto operator""_ksym()->KSymT<chars_ta...>& { return KSymT<chars_ta...>::s; }
struct KSym {
virtual void onRegister() {}
virtual std::string_view zview_get() = 0;
};
template <char... chars_ta>
struct KSymT : KSym {
inline static KSymT s;
// We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
inline static constexpr char z[sizeof...(chars_ta) + 1] = { chars_ta..., '\0' };
inline static constexpr UIntPk n = sizeof...(chars_ta);
// We can have properties, we don't need anything to be constexpr for Rs
virtual std::string_view zview_get() { return std::string_view(z); };
//#KSym-support compare with `Af_CmdArgs`
inline bool operator==(const Af_CmdArgs& cmd) {
return (cmd.argl[0] == n && memcmp(cmd.argv[0], z, n) == 0);
}
};
I was struggling with a similar problem and finally came up with a concise implementation that unpacks the string literal into a char... template parameter pack and without using the GNU literal operator template extension:
#include <utility>
template <char ...Chars>
struct type_string_t {
static constexpr const char data[sizeof...(Chars)] = {Chars...};
};
template <char s(std::size_t), std::size_t ...I>
auto type_string_impl(std::index_sequence<I...>) {
return type_string_t<s(I)...>();
}
#define type_string(s) \
decltype (type_string_impl<[] -> constexpr (std::size_t i) {return s[i];}> \
(std::make_index_sequence<sizeof (s)>()))
static_assert (std::is_same<type_string("String_A"),
type_string("String_A")>::value);
static_assert (!std::is_same<type_string("String_A"),
type_string("String_B")>::value);
A major caveat: this depends on a C++20 feature (class values as non-type template arguments; P0732, P1907), which (as of December 2020) is only (partially) implemented in GCC 9 and later (preprocessor feature test: (__cpp_nontype_template_args >= 201911L) || (__GNUG__ >= 9)). However, since the feature is standard, it is only a matter of time before other compilers catch up.
Another C++20 solution I don't see mentioned, but which was sufficiently simple and suitable for my own needs, is to use a constexpr lambda as the NTTP returning the string:
#include <string_view>
template<auto getStrLambda>
struct MyType {
static constexpr std::string_view myString{getStrLambda()};
};
int main() {
using TypeWithString = MyType<[]{return "Hello world!";}>;
return 0;
}
Compiler explorer example here.
here is a solution and extensions/examples
my solution extends https://ctrpeach.io/posts/cpp20-string-literal-template-parameters/
#include <iostream>
#include <algorithm>
#include <string>
template<size_t N>
struct StringLiteral {
char value[N];
constexpr StringLiteral(const char(&str)[N]) {
std::copy_n(str, N, value);
}
};
template <StringLiteral T>
struct String {
static constexpr std::string str() {
return T.value;
}
};
template <typename... Strings>
struct JoinedString {
static constexpr std::string str() {
return (Strings::str() + ...);
}
};
template <typename Delim, typename String, typename... Strings>
struct DelimJoinedString {
static constexpr std::string str() {
if constexpr (sizeof...(Strings))
return JoinedString<String, Delim, DelimJoinedString<Delim, Strings...>>::str();
else
return String::str();
}
};
int main() {
// "123"
using s123 = String<"123">;
std::cout << s123::str() << "\n";
// "abc"
using abc = String<"abc">;
std::cout << abc::str() << "\n";
// "abc123abc123"
using abc123abc123 = JoinedString<abc, s123, abc, s123>;
std::cout << abc123abc123::str() << "\n";
// "abc, 123"
using abccomma123 = DelimJoinedString<String<", ">, abc, s123>;
std::cout << abccomma123::str() << "\n";
// "abc, 123, 123, abc"
using commaabc123123abc = DelimJoinedString<String<", ">, abc, s123, s123, abc>;
std::cout << commaabc123123abc::str() << "\n";
return 0;
}
a string literal "my string", so I guess const char * const
Actually, string literals with n visible characters are of type const char[n+1].
#include <iostream>
#include <typeinfo>
template<class T>
void test(const T& t)
{
std::cout << typeid(t).name() << std::endl;
}
int main()
{
test("hello world"); // prints A12_c on my compiler
}