C++20 string literal template argument working example - c++

Could someone post a minimal reproducible example of C++20's feature string template as template argument?
this one from ModernCpp does not compile:
template<std::basic_fixed_string T>
class Foo {
static constexpr char const* Name = T;
public:
void hello() const;
};
int main() {
Foo<"Hello!"> foo;
foo.hello();
}
I've managed to write a working solution based on this Reddit post:
#include <iostream>
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; }
// not mandatory anymore
auto operator<=>(const FixedString&) const = default;
};
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;
template<FixedString Name>
class Foo
{
public:
auto hello() const { return Name; }
};
int main()
{
Foo<"Hello!"> foo;
std::cout << foo.hello() << std::endl;
}
Live Demo
but does provide a custom implementation for a fixed string. So what should be the state-of-the-art implementation by now?

P0259 fixed_string has been retired on the basis that most of its use cases are better achieved via P0784 More constexpr containers (aka constexpr destructors and transient allocation) - i.e. being able to use std::string itself within constexpr context.
Of course, even if you can use std::string in constexpr, that doesn't make it usable as an NTTP, but it doesn't look like we're going to get a structural string class into the Standard any time soon. I would recommend using your own structural string class for now, being ready to alias it to an appropriate third-party class should one emerge in a popular library, or to a standard one if and when that happens.

Related

c++: using constexpr to XOR data doesn't work

Here is my code:
template<int... I>
class MetaString1
{
public:
constexpr MetaString1(constexpr char* str)
: buffer_{ encrypt(str[I])... } { }
const char* decrypt()
{
for (int i = 0; i < sizeof...(I); ++i)
buffer_[i] = decrypt1(buffer_[i]);
buffer_[sizeof...(I)] = 0;
return buffer_;
}
private:
constexpr char encrypt(constexpr char c) const { return c ^ 0x55; }
constexpr char decrypt1(constexpr char c) const { return encrypt(c); }
private:
char buffer_[sizeof...(I)+1];
};
#define OBFUSCATED1(str) (MetaString1<0, 1, 2, 3, 4, 5>(str).decrypt())
int main()
{
constexpr char *var = OBFUSCATED1("Post Malone");
std::cout << var << std::endl;
return 1;
}
This is the code from the paper that I'm reading Here. The Idea is simple, to XOR the argument of OBFUSCATED1 and then decrypt back to original value.
The problem that I'm having is that VS 2017 gives me error saying function call must have a constant value in constant expression.
If I only leave OBFUSCATED1("Post Malone");, I have no errors and program is run, but I've noticed that if I have breakpoints in constexpr MetaString1 constructor, the breakpoint is hit, which means that constexpr is not evaluated during compile time. As I understand it's because I don't "force" compiler to evaluate it during compilation by assigning the result to a constexpr variable.
So I have two questions:
Why do I have error function call must have a constant value in constant expression?
Why do people use template classes when they use constexpr functions? As I know template classes get evaluated during compilation, so using template class with constexpr is just a way to push compiler to evaluate those functions during compilation?
You try to assign a non constexpr type to a constexpr type variable,
what's not possible
constexpr char *var = OBFUSCATED1("Post Malone")
// ^^^ ^^^^^^^^^^^
// type of var is constexpr, return type of OBFUSCATED1 is const char*
The constexpr keyword was introduced in C++11, so before you had this keyword you had to write complicated TMP stuff to make the compiler do stuff at compile time. Since TMP is turing complete you theoretically don't need something more than TMP, but since TMP is slow to compile and ugly to ready, you are able to use constexpr to express things you want evaluate at compile time in a more readable way. Although there is no correlation between TMP and constexpr, what means, you are free to use constexpr without template classes.
To achieve what you want, you could save both versions of the string:
template <class T>
constexpr T encrypt(T l, T r)
{
return l ^ r;
}
template <std::size_t S, class U>
struct in;
template <std::size_t S, std::size_t... I>
struct in<S, std::index_sequence<I...>>
{
constexpr in(const char str[S])
: str_{str[I]...}
, enc_{encrypt(str[I], char{0x12})...}
{}
constexpr const char* dec() const
{
return str_;
}
constexpr const char* enc() const
{
return enc_;
}
protected:
char str_[S];
char enc_[S];
};
template <std::size_t S>
class MetaString1
: public in<S, std::make_index_sequence<S - 1>>
{
public:
using base1_t = in<S, std::make_index_sequence<S - 1>>;
using base1_t::base1_t;
constexpr MetaString1(const char str[S])
: base1_t{str}
{}
};
And use it like this:
int main()
{
constexpr char str[] = "asdffasegeasf";
constexpr MetaString1<sizeof(str)> enc{str};
std::cout << enc.dec() << std::endl;
std::cout << enc.enc() << std::endl;
}

Had to specify upper limit while evaluating the length of C-style string through template metaprogramming

I recently starting playing around with template metaprogramming in C++, and been trying to evaluate the length of a C-style string.
I've had some success with this bit of code
template <const char *str, std::size_t index>
class str_length {
public:
static inline std::size_t val() {
return (str[index] != '\0') ? (1 + str_length<str, index + 1>::val()) : 0;
}
};
template <const char *str>
class str_length <str, 500> {
public:
static inline std::size_t val() {
return 0;
}
};
extern const char bitarr[] { "0000000000000000000" };
int main() {
std::cout << str_length<bitarr, 0>::val() << std::endl;
getchar();
return 0;
}
However, I had to set a "upper limit" of 500 by creating a specialization of str_length. Omitting that would cause my compiler to run indefinitely (presumably creating infinite specializations of str_length).
Is there anything I could do to not specify the index = 500 limit?
I'm using VC++2015 if that helps.
Oh, and I'm not using constexpr because VC++ doesn't quite support the C++14 extended constexpr features yet. (https://msdn.microsoft.com/en-us/library/hh567368.aspx#cpp14table)
The usual way to stop infinite template instantiation, in these situation, is by using specialization; which is orthogonal to constexpr-ness of anything. Reviewing the list of additional stuff that extended constexpr allows in C++14, I see nothing in the following example that needs extended constexpr support. gcc 6.1.1 compiles this in -std=c++11 compliance mode, FWIW:
#include <iostream>
template<const char *str, size_t index, char c> class str_length_helper;
template <const char *str>
class str_length {
public:
static constexpr std::size_t val()
{
return str_length_helper<str, 0, str[0]>::val();
}
};
template<const char *str, std::size_t index, char c>
class str_length_helper {
public:
static constexpr std::size_t val()
{
return 1+str_length_helper<str, index+1, str[index+1]>::val();
}
};
template<const char *str, std::size_t index>
class str_length_helper<str, index, 0> {
public:
static constexpr std::size_t val()
{
return 0;
}
};
static constexpr char bitarr[] { "0000000000000000000" };
int main() {
std::cout << str_length<bitarr>::val() << std::endl;
getchar();
return 0;
}
Note, however, that the character string itself must be constexpr. As the comments noted, this is of dubious practical use; but there's nothing wrong with messing around in this manner in order to get the hang of metaprogramming.
The key point is the use of specialization, and the fact that in order to be able to use str[index] as a template parameter, str must be constexpr.

std::hash value on char* value and not on memory address?

As stated in this link:
There is no specialization for C strings. std::hash produces a hash of the value of the pointer (the memory address), it does not examine the contents of any character array.
Which means that with the same char* value, different hashcodes could be produced. For example, having this code:
//MOK and MOV are template arguments
void emit(MOK key, MOV value) {
auto h = hash<MOK>()(key);
cout<<"key="<<key<<" h="<<h<<endl;
...
This is the output produced by calling 4 times emit() on the same key (with MOK=char*) value (but 4 different tokens/string objects):
key=hello h=140311481289184
key=hello h=140311414180320
key=hello h=140311414180326
key=hello h=140311481289190
How can I obtain the same hash code for char*? I'd prefer not to use boost
There is of course the trivial (and slow) solution of creating a temporary std::string and hashing that one. If you don't want to do this, I'm afraid you will have to implement your own hash function. Sadly enough, the current C++ standard library doesn't provide general purpose hash algorithms disentangled from object-specific hash solutions. (But there is some hope this could change in the future.)
Suppose you had a function
std::size_t
hash_bytes(const void * data, std::size_t size) noexcept;
that would take an address and a size and return you a hash computed from the that many bytes following that address. With the help of that function, you could easily write
template <typename T>
struct myhash
{
std::size_t
operator()(const T& obj) const noexcept
{
// Fallback implementation.
auto hashfn = std::hash<T> {};
return hashfn(obj);
}
};
and then specialize it for the types you're interested in.
template <>
struct myhash<std::string>
{
std::size_t
operator()(const std::string& s) const noexcept
{
return hash_bytes(s.data(), s.size());
}
};
template <>
struct myhash<const char *>
{
std::size_t
operator()(const char *const s) const noexcept
{
return hash_bytes(s, std::strlen(s));
}
};
This leaves you only with the exercise of implementing hash_bytes. Fortunately, there are some fairly good hash functions that are rather easy to implement. My go-to algorithm for simple hashing is the Fowler-Noll-Vo hash function. You can implement it in five lines of code; see the linked Wikipedia article.
If you want to get a bit fancy, consider the following implementation. First, I define a generic template that can be specialized for any version of the FNV-1a hash function.
template <typename ResultT, ResultT OffsetBasis, ResultT Prime>
class basic_fnv1a final
{
static_assert(std::is_unsigned<ResultT>::value, "need unsigned integer");
public:
using result_type = ResultT;
private:
result_type state_ {};
public:
constexpr
basic_fnv1a() noexcept : state_ {OffsetBasis}
{
}
constexpr void
update(const void *const data, const std::size_t size) noexcept
{
const auto cdata = static_cast<const unsigned char *>(data);
auto acc = this->state_;
for (auto i = std::size_t {}; i < size; ++i)
{
const auto next = std::size_t {cdata[i]};
acc = (acc ^ next) * Prime;
}
this->state_ = acc;
}
constexpr result_type
digest() const noexcept
{
return this->state_;
}
};
Next, I provide aliases for the 32 and 64 bit versions. The parameters were taken from Landon Curt Noll's website.
using fnv1a_32 = basic_fnv1a<std::uint32_t,
UINT32_C(2166136261),
UINT32_C(16777619)>;
using fnv1a_64 = basic_fnv1a<std::uint64_t,
UINT64_C(14695981039346656037),
UINT64_C(1099511628211)>;
Finally, I provide type meta-functions to select a version of the algorithm given the wanted number of bits.
template <std::size_t Bits>
struct fnv1a;
template <>
struct fnv1a<32>
{
using type = fnv1a_32;
};
template <>
struct fnv1a<64>
{
using type = fnv1a_64;
};
template <std::size_t Bits>
using fnv1a_t = typename fnv1a<Bits>::type;
And with that, we're good to go.
constexpr std::size_t
hash_bytes(const void *const data, const std::size_t size) noexcept
{
auto hashfn = fnv1a_t<CHAR_BIT * sizeof(std::size_t)> {};
hashfn.update(data, size);
return hashfn.digest();
}
Note how this code automatically adapts to platforms where std::size_t is 32 or 64 bits wide.
I've had to do this before and ended up writing a function to do this, with essentially the same implementation as Java's String hash function:
size_t hash_c_string(const char* p, size_t s) {
size_t result = 0;
const size_t prime = 31;
for (size_t i = 0; i < s; ++i) {
result = p[i] + (result * prime);
}
return result;
}
Mind you, this is NOT a cryptographically secure hash, but it is fast enough and yields good results.
In C++17 you should use std::hash<std::string_view> which works seamlessly since const char* can be implicitly converted to it.
Since C++17 added std::string_view including a std::hash specialization for it you can use that to compute the hash value of a C-string.
Example:
#include <string_view>
#include <cstring>
static size_t hash_cstr(const char *s)
{
return std::hash<std::string_view>()(std::string_view(s, std::strlen(s)));
}
If you have to deal with a pre-C++17 compiler you can check your STL for an implementation defined hash function and call that.
For example, libstdc++ (which is what GCC uses by default) provides std::_Hash_bytes which can be called like this:
#include <functional>
// -> which finally includes /usr/include/c++/$x/bits/hash_bytes.h
#include <cstring>
static size_t hash_cstr_gnu(const char *s)
{
const size_t seed = 0;
return std::_Hash_bytes(s, std::strlen(s), seed);
}
You can use std::collate::hash
e.g. https://www.cplusplus.com/reference/locale/collate/hash/

How to create static strings from types at compile time

I have a bunch of types that have a name. (They have more features, but for the sake of this discussion only the name is relevant.) These types and their names are setup at compile-time using a macro:
#define DEFINE_FOO(Foo_) \
struct Foo_ : public foo_base<Foo_> { \
static char const* name() {return #Foo_;} \
}
The types are then combined in compile-time lists (classic simple recursive compile-time lists), from which I need to create the list's name by concatenating the names of its objects:
template<class Foo, class Tail = nil>
struct foo_list {
static std::string name_list() {return Foo::name() + "-" + Tail::name();}
};
template<class Foo>
struct foo_list<Foo,nil> {
static std::string name_list() {return Foo::name();}
};
The code is boiled down here to the point where it might contain errors, but in practice this works pretty well.
Except that it creates and then copies around rather long strings at runtime which represent types that actually are well-known at compile-time. Since this is a rather performance-sensitive piece of code that runs on embedded devices, I'd like to change this so that
the list's string is ideally created at compile-time, or, if there's no way to do that, once at runtime, and
I only need to copy around a pointer to a C string, since, according to #1, the strings are fixed in memory.
This compiles with C++03, which we're stuck with right now.
How can I do this?
(In case this enlarges the arsenal of dirty tricks employable for this: The names of the foo objects are only ever created and read by code, and only the foo_list name strings are expected to be human-readable.)
You probably want to look at boost's mpl::string. Example to follow once my coffee has kicked in...
EDIT: So coffee has kicked in... :)
#include <iostream>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/string.hpp>
#include <boost/mpl/vector.hpp>
namespace mpl = boost::mpl;
struct foo
{
typedef mpl::string<'foo'> name;
};
struct bar
{
typedef mpl::string<'bar'> name;
};
struct gah
{
typedef mpl::string<'gah'> name;
};
namespace aux
{
template <typename string_type, typename It, typename End>
struct name_concat
{
typedef typename mpl::insert_range<string_type, typename mpl::end<string_type>::type, typename mpl::deref<It>::type::name>::type base;
typedef typename aux::name_concat<base, typename mpl::next<It>::type, End>::name name;
};
template <typename string_type, typename End>
struct name_concat<string_type, End, End>
{
typedef string_type name;
};
}
template <typename ...Types>
struct type_list
{
typedef mpl::string<> base;
typedef mpl::vector<Types...> type_seq;
typedef typename aux::name_concat<base, typename mpl::begin<type_seq>::type, typename mpl::end<type_seq>::type>::name name;
};
int main(void)
{
typedef typename type_list<foo, bar, gah>::name tlist_name;
std::cout << mpl::c_str<tlist_name>::value << std::endl;
}
I'm sure you are more than competent enough to tweak the above for your situation. NOTE: you will have to ignore the multi-character constant warnings...
Couple of more caveats: the multi-character constant passed to mpl::string cannot be more than 4 characters, so, some how it has to be chunked (or constructed of individual characters), so a long string could be, mpl::string<'this', ' is ', 'a lo', 'ng s', 'trin', 'g'> If this is cannot be done, then the above will not work.. :/
I came up with following solution:
Type is generated as:
const char foo_str [] = "foo";
struct X
{
static const char *name() { return foo_str; }
enum{ name_size = sizeof(foo_str) };
};
Keypoint here is that we know length of its name at compile time. That allow us to calculate total length of names in typelist:
template<typename list>
struct sum_size
{
enum
{
value = list::head::name_size - 1 +
sum_size<typename list::tail>::value
};
};
template<>
struct sum_size<nil>
{
enum { value = 0 };
};
Knowing total length at compile time, we can allocate static buffer of appropriate size for concatenation of strings - so there will be no any dynamic allocations:
static char result[sum_size<list>::value + 1];
That buffer should be filled at runtime, but only once, and that operation is pretty cheap (much faster than previous solution with dynamic allocation of strings and their concatenation in recursion):
template<typename list>
const char *concate_names()
{
static char result[sum_size<list>::value + 1];
static bool calculated = false;
if(!calculated)
{
fill_string<list>::call(result);
calculated = true;
}
return result;
}
Here is full code:
Live Demo on Coliru
#include <algorithm>
#include <iostream>
using namespace std;
/****************************************************/
#define TYPE(X) \
const char X ## _str [] = #X; \
struct X \
{ \
static const char *name() { return X ## _str; } \
enum{ name_size = sizeof(X ## _str) }; \
}; \
/**/
/****************************************************/
struct nil {};
template<typename Head, typename Tail = nil>
struct List
{
typedef Head head;
typedef Tail tail;
};
/****************************************************/
template<typename list>
struct sum_size
{
enum { value = list::head::name_size - 1 + sum_size<typename list::tail>::value };
};
template<>
struct sum_size<nil>
{
enum { value = 0 };
};
/****************************************************/
template<typename list>
struct fill_string
{
static void call(char *out)
{
typedef typename list::head current;
const char *first = current::name();
fill_string<typename list::tail>::call
(
copy(first, first + current::name_size - 1, out)
);
}
};
template<>
struct fill_string<nil>
{
static void call(char *out)
{
*out = 0;
}
};
/****************************************************/
template<typename list>
const char *concate_names()
{
static char result[sum_size<list>::value + 1];
static bool calculated = false;
if(!calculated)
{
fill_string<list>::call(result);
calculated = true;
}
return result;
}
/****************************************************/
TYPE(foo)
TYPE(bar)
TYPE(baz)
typedef List<foo, List<bar, List<baz> > > foo_list;
int main()
{
cout << concate_names<foo_list>() << endl;
}
Output is:
foobarbaz
P.S. How do you use concatenated string? Maybe we don't need to generate concatenated string at all, reducing data space requirement.
For example if you just need to print string - then
template<typename list>
void print();
will be sufficient. But downside is that while decreasing data size - that could lead to increased size of code.
You could make the string static and you only have to construct the string once at runtime and only when it is needed.
Then you return a const reference of them so that there wouldn't be any unnecessary copying.
Example:
template<class Foo, class Tail = nil>
struct foo_list {
static const std::string& name_list() {
static std::string names = Foo::name() + std::string("-") + Tail::name();
return names;
}
};
template<class Foo>
struct foo_list<Foo,nil> {
static const std::string& name_list() {
static std::string names = Foo::name();
return names;
}
};
Might not be the exact code that you'll write, but I think that gives you the point. Also, you could return a const char* by doing names.c_str().
You can consider using an external build step instead of an in-language solution. For example, you could write a tool based on Clang to parse the relevant files and create the T::name implementations automatically in another TU. Then integrate it into your build script.
If we could assume that your only requirement is to actually stream the names of the classes - meaning you don't need the concatenated strings at other places as a whole - you could simply defer streaming but still benefit from meta-programming (as Evgeny already pointed out).
While this solution doesn't satisfy your requirement #1 (one concatenated string), I'd still like to point out a solution for other readers.
Instead of going through a compile-time list of types, the idea is to build a sequence of addresses from all T::name() functions and pass that into a streaming function when needed. This is possible because variables with external linkage can be used as template non-type arguments. Your mileage may vary in terms of data and code size of course, but unless you are in a high-performance environment I expect this approach to be at least equally suitable as no additional strings have to be created at runtime.
Note that I deliberately used variadic templates (not available in C++03) because it's much more readable and simpler to reason about.
"Fiddle" available here.
#include <ostream>
#include <boost/core/ref.hpp>
#include <boost/bind.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
namespace mpl = boost::mpl;
template<typename>
class foo_base
{};
#define DECLARE_FOO(Foo_) \
struct Foo_ : public foo_base<Foo_> { \
static char const* name() {return #Foo_;} \
};
// our own integral constant because mpl::integral_c would have to be specialized anyway
template<typename T, T Value>
struct simple_integral_c
{
operator T() const { return Value; }
};
template<typename T, T ...Values>
struct ic_tuple : mpl::vector<simple_integral_c<T, Values>...>
{};
typedef const char*(*NameFunction)();
template <NameFunction ...Functions>
struct function_list : ic_tuple<NameFunction, Functions...>
{};
template <typename ...Types>
struct function_of_list : function_list<&Types::name...>
{};
struct print_type
{
void operator ()(std::ostream& os, NameFunction name)
{
if (nth++)
os << "-";
os << name();
}
print_type(): nth(0) {}
private:
int nth;
};
// streaming function
template<NameFunction ...Functions>
std::ostream& operator <<(std::ostream& os, function_list<Functions...>)
{
mpl::for_each<function_list<Functions...>>(
boost::bind<void>(print_type(), boost::ref(os), _1)
);
return os;
}
These days with C++14 one would probably write the solution with a powerful library like hana, see this hana fiddle.

Passing a string literal as a type argument to a class template

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
}