C-Style Strings as template arguments?
No, you can't work with string literals at compile time. The best you can get are the weird multicharacter literals (e.g. 'abcd'
) which some compile-time parsers use. They are mentioned in §2.13.2.1:
An ordinary character literal that contains more than one c-char is a multicharacter literal. A multicharac- ter literal has type int and implementation-defined value.
In C++0x there might be ways around this limitations though with the new string literals, Arctic Interactive has an interesting article on that.
A string literal cannot be used as a template argument.
Update: Nowadays, a few years after this question was asked and answered, it is possible to use string literals as template arguments. With C++11, we can use characters packs as template arguments (template<char ...c>
) and it is possible to pass a literal string to such a template.
This would work, however:
template <char const *str>
struct X
{
const char *GetString() const
{
return str;
}
};
char global_string[] = "String";
int main()
{
X<global_string> x;
cout<<x.GetString();
}
I known, this topic is a bit old but I put this comment if anyone is interested. I achieved templates with passing literal string as argument with combination of MACROS.
I made a code example,
#include <stdio.h>
#include <iostream>
#include <vector>
#include <memory>
#include <string.h>
using namespace std;
#define MAX_CONST_CHAR 100
#define MIN(a,b) (a)<(b)?(a):(b)
#define _T(s)\
getChr(s,0),\
getChr(s,1),\
getChr(s,2),\
getChr(s,3),\
getChr(s,4),\
getChr(s,5),\
getChr(s,6),\
getChr(s,7),\
getChr(s,8),\
getChr(s,9),\
getChr(s,10),\
getChr(s,11),\
getChr(s,12),\
getChr(s,13),\
getChr(s,14),\
getChr(s,15),\
getChr(s,16),\
getChr(s,17),\
getChr(s,18),\
getChr(s,19),\
getChr(s,20),\
getChr(s,21),\
getChr(s,22),\
getChr(s,23),\
getChr(s,24),\
getChr(s,25),\
getChr(s,26),\
getChr(s,27),\
getChr(s,28),\
getChr(s,29),\
getChr(s,30),\
getChr(s,31),\
getChr(s,32),\
getChr(s,33),\
getChr(s,34),\
getChr(s,35),\
getChr(s,36),\
getChr(s,37),\
getChr(s,38),\
getChr(s,39),\
getChr(s,40),\
getChr(s,41),\
getChr(s,42),\
getChr(s,43),\
getChr(s,44),\
getChr(s,45),\
getChr(s,46),\
getChr(s,47),\
getChr(s,48),\
getChr(s,49),\
getChr(s,50),\
getChr(s,51),\
getChr(s,52),\
getChr(s,53),\
getChr(s,54),\
getChr(s,55),\
getChr(s,56),\
getChr(s,57),\
getChr(s,58),\
getChr(s,59),\
getChr(s,60),\
getChr(s,61),\
getChr(s,62),\
getChr(s,63),\
getChr(s,64),\
getChr(s,65),\
getChr(s,66),\
getChr(s,67),\
getChr(s,68),\
getChr(s,69),\
getChr(s,70),\
getChr(s,71),\
getChr(s,72),\
getChr(s,72),\
getChr(s,72),\
getChr(s,73),\
getChr(s,74),\
getChr(s,75),\
getChr(s,76),\
getChr(s,77),\
getChr(s,78),\
getChr(s,79),\
getChr(s,80),\
getChr(s,81),\
getChr(s,82),\
getChr(s,83),\
getChr(s,84),\
getChr(s,85),\
getChr(s,86),\
getChr(s,87),\
getChr(s,88),\
getChr(s,89),\
getChr(s,90),\
getChr(s,91),\
getChr(s,92),\
getChr(s,93),\
getChr(s,94),\
getChr(s,95),\
getChr(s,96),\
getChr(s,97),\
getChr(s,98),\
getChr(s,99),\
getChr(s,100)
#define getChr(name, ii) ((MIN(ii,MAX_CONST_CHAR))<sizeof(name)/sizeof(*name)?name[ii]:0)
template <char... Chars_>
class E {
public:
string *str;
E(){
std::vector<char> vec = {Chars_...};
str = new string(vec.begin(),vec.end());
}
~E()
{
delete str;
}
};
int main(int argc, char *argv[])
{
E<_T("Any template can pass const strings literals")> e;
printf("%s",e.str->c_str());
}
This works with g++ 4.6 and passing argument -std=c++0x, and have a limit of 100 char but, of course, can be as greater as you want. Maybe this technique is not well optimized, but it will be more productive than declare the needed external variables (I'm sure ;) )
Constraints: The literal string must be one and last argument of the template due the passing of variadics arguments.
EDIT: Thanks to Padek he tested that this piece of code also it works with Visual Studio 2017 but changing strlen by sizeof(name)/sizeof(*name).
Sorry to post on such an old question, but here's what I feel is the cleanest approach to actually pass a literal as the argument without using storage.
Encode the string as a type:
template <char... chars>
using tstring = std::integer_sequence<char, chars...>;
Create a user defined literal operator:
template <typename T, T... chars>
constexpr tstring<chars...> operator""_tstr() { return { }; }
And use partial specialization to recover the character data as needed:
template <typename>
struct X;
template <char... elements>
struct X<tstring<elements...>> {
const char* GetString() const
{
static constexpr char str[sizeof...(elements) + 1] = { elements..., '\0' };
return str;
}
};
This allows you to write:
X<decltype("my_string"_tstr)>
The user defined literal uses non-standard (n3599) functionality not in C++14 but that is supported by recent GCC and Clang builds, and hopefully will be reconsidered for C++1z.