I am trying to obtain the length of a string passed as a template argument using C++11. Here is what I have found so far:
#include <iostream>
#include <cstring>
extern const char HELLO[] = "Hello World!!!";
template<const char _S[]>
constexpr size_t len1() { return sizeof(_S); }
template<const char _S[]>
constexpr size_t len2() { return std::strlen(_S); }
template<const char _S[], std::size_t _Sz=sizeof(_S)>
constexpr size_t len3() { return _Sz-1; }
template<unsigned int _N>
constexpr size_t len5(const char(&str)[_N])
{
return _N-1;
}
int main() {
enum {
l1 = len1<HELLO>(),
// l2 = len2<HELLO>() does not compile
l3 = len3<HELLO>(),
l4 = len3<HELLO, sizeof(HELLO)>(),
l5 = len5(HELLO),
};
std::cout << l1 << std::endl; // outputs 4
// std::cout << l2 << std::endl;
std::cout << l3 << std::endl; // outputs 3
std::cout << l4 << std::endl; // outputs 14
std::cout << l5 << std::endl; // outputs 14
return 0;
}
I am not very surprised with the results, I understand that the size of the array is lost in the case of len1() and len2(), although the information is present at compile time.
Is there a way to pass the information about the size of the string to the template as well? Something like:
template<const char _S[unsigned int _N]>
constexpr size_t len6() { return _N-1; }
[Edit with context and intent]
I gave up trying to concatenate a set of strings at compile time so I am trying to do it at initialization time. Writing something like a().b().c().str() would output "abc" while a().b().str() would output "ab"
Using templates, a().b() creates a type of B with a parent type A. a().b().c() creates a type C with a parent type B which has a parent type A, etc.
Given a type B with a parent A, this is a unique type and it can have it's own static buffer to hold the concatenation (this is why l5 isn't good for me). I could then strcpy` each one consecutively in a static buffer. I don't want to use a dynamically allocated buffer because my allocator is not necessarily configured at this point.
The size of that buffer which should be big enough to hold the string associated with A and the string associated with B is what I am trying to figure out. I can get it to work if I explicitly sizeof() as an extra template parameter (as done with l4 in the snippet above), but that make the whole code heavy to read and cumbersome to use.
[Edit 2] I marked the answer that was most helpful - but Yakk's answer was also good on gcc but except it did not compile with Visual Studio.
My understanding at this point is that we cannot rely on const char [] with external linkage to provide their size. It may work locally (if the template is compiled in the same unit as the symbol), but it won't work if the const char[] is in a header file to be used in multiple places.
So I gave up on trying to extract the length from the const char* template paramter and decided to live with l4 where the sizeof() is also provided to the template arguments.
For those who are curious how the whole thing turned out, I pasted a full working sample on ideone: http://ideone.com/A0JwO8
I can now write Path<A>::b::c::path() and get the corresponding "b.c" string in a static buffer at initialization.
constexpr std::size_t length( const char * str ) {
return (!str||!*str)?0:(1+length(str+1));
}
template<const char * String>
constexpr size_t len() { return length(String); }
extern constexpr const char HELLO[] = "Hello World!!!";
live example. Recursion wouldn't be needed in C++14.
To concatenate string at compile time,
with gnu extension, you may do:
template<typename C, C...cs> struct Chars
{
using str_type = C[1 + sizeof...(cs)];
static constexpr C str[1 + sizeof...(cs)] = {cs..., 0};
constexpr operator const str_type&() const { return str; }
};
template<typename C, C...cs> constexpr C Chars<C, cs...>::str[1 + sizeof...(cs)];
// Requires GNU-extension
template <typename C, C...cs>
constexpr Chars<C, cs...> operator""_cs() { return {}; }
template <typename C, C...lhs, C...rhs>
constexpr Chars<C, lhs..., rhs...>
operator+(Chars<C, lhs...>, Chars<C, rhs...>) { return {}; }
With usage
constexpr auto hi = "Hello"_cs + " world\n"_cs;
std::cout << hi;
Demo
Without gnu extension, you have to use some MACRO to transform literal into char sequence, as I do there.
Related
Context:
In my company we generate a lot of types based on IDL files. Some of the types require special logic so they are handcoded but follow the same pattern as the generated ones. We have a function which all types must implement which is a name function. This will return the type name as a char* string and the function is constexpr.
Problem:
The problem is regarding collections which could contain other collections nested potentially N number of times. I therefore am trying to concatenate two or more char* strings at compile time.
Pseudocode of what I want to achieve:
template <typename T>
constexpr char* name()
{
constexpr char* collectionName = "std::vector";
constexpr char* containedTypeName = name<T>();
return concat(collectionName, "<", containedTypeName, ">");
}
Note:
There are examples out there which does something like this but is done with char[] or the use of static variables.
The question:
How can I make a constexpr function which return a char* which consists of two or more concatenated char* strings at compile time? I am bound to C++17.
From constexpr you cannot return char* which is constructed there... You must return some compile time known(also its size) constant thingy.
A possible solution could be something like:
#include <cstring>
// Buffer to hold the result
struct NameBuffer
{
// Hardcoded 128 bytes!!!!! Carefully choose the size!
char data[128];
};
// Copy src to dest, and return the number of copied characters
// You have to implement it since std::strcpy is not constexpr, no big deal.
constexpr int constexpr_strcpy(char* dest, const char* src);
//note: in c++20 make it consteval not constexpr
template <typename T>
constexpr NameBuffer name()
{
// We will return this
NameBuffer buf{};
constexpr const char* collectionName = "std::vector";
constexpr const char* containedTypeName = "dummy";
// Copy them one by one after each other
int n = constexpr_strcpy(buf.data, collectionName);
n += constexpr_strcpy(buf.data + n, "<");
n += constexpr_strcpy(buf.data + n, containedTypeName);
n += constexpr_strcpy(buf.data + n, ">");
// Null terminate the buffer, or you can store the size there or whatever you want
buf.data[n] = '\0';
return buf;
}
Demo
And since the returned char* is only depends on the template parameter in your case, you can create templated variables, and create a char* to them, and it can act like any other char*...
EDIT:
I have just realized that your pseudo code will never work!! Inside name<T>() you are trying to call name<T>().
You must redesign this!!! But! With some hack you can determine the size at compile time somehow for example like this:
#include <cstring>
#include <iostream>
template<std::size_t S>
struct NameBuffer
{
char data[S];
};
// Copy src to dest, and return the number of copied characters
constexpr int constexpr_strcpy(char* dest, const char* src)
{
int n = 0;
while((*(dest++) = *(src++))){ n++; }
return n;
}
// Returns the len of str without the null term
constexpr int constexpr_strlen(const char* str)
{
int n = 0;
while(*str) { str++; n++; }
return n;
}
// This template parameter does nothing now...
// I left it there so you can see how to create the template variable stuff...
//note: in c++20 make it consteval not constexpr
template <typename T>
constexpr auto createName()
{
constexpr const char* collectionName = "std::vector";
constexpr const char* containedTypeName = "dummy";
constexpr std::size_t buff_size = constexpr_strlen(collectionName) +
constexpr_strlen(containedTypeName) +
2; // +1 for <, +1 for >
/// +1 for the nullterm
NameBuffer<buff_size + 1> buf{};
/// I'm lazy to rewrite, but now we already calculated the lengths...
int n = constexpr_strcpy(buf.data, collectionName);
n += constexpr_strcpy(buf.data + n, "<");
n += constexpr_strcpy(buf.data + n, containedTypeName);
n += constexpr_strcpy(buf.data + n, ">");
buf.data[n] = '\0';
return buf;
}
// Create the buffer for T
template<typename T>
static constexpr auto name_buff_ = createName<T>();
// point to the buffer of type T. It can be a function too as you wish
template<typename T>
static constexpr const char* name = name_buff_<T>.data;
int main()
{
// int is redundant now, but this is how you could use this
std::cout << name<int> << '\n';
return 0;
}
Demo
I was implementing the circular array data structure whose code looks like this:
struct CircularArrayException : public std::exception {
std::string msg;
CircularArrayException(const std::string arg_msg)
: msg{"CircularArrayException: " + arg_msg} {}
const char * what () const throw () {
return msg.c_str();
}
};
template <typename T>
class CircularArray {
public:
const size_t array_size;
std::unique_ptr<T> uptr_arr;
size_t occupied_size = 0;
int front_idx = -1;
int back_idx = -1;
CircularArray(const CircularArray& ca) = delete;
CircularArray& operator=(const CircularArray& ca) = delete;
CircularArray(
const size_t arg_array_size
): array_size{arg_array_size} {
uptr_arr = std::make_unique<T>(array_size);
};
};
After the implementation I tested the implementation with CircularArray<char> and it works fine.
But, then I realized that we use std::make_unique<char[]>(num_elements) to declare a unique_ptr to an array as opposed to std::make_unique<char>(num_elements). But, even then the code seems to work fine. I looked the documentation of std::make_unique here and couldn't understand the explanation of the (2)nd signature. Can anyone help me out to understand the difference and why my code works?
Here is the what is written on cppreference for the (2) signature:
template< class T >
unique_ptr<T> make_unique( std::size_t size );
(2) (since C++14)
(only for array types with unknown bound)
Constructs an array of unknown bound T. This overload participates in overload resolution only if T is an array of unknown bound. The function is equivalent to: unique_ptr<T>(new typename std::remove_extent<T>::type[size]())
Here is the goldbolt link: https://godbolt.org/z/K9h3qTeTW
std::make_unique<char>(65); creates a pointer to a single character initialised with the value 65 ('A'). std::make_unique<char[]>(65) creates an array with 65 elements.
If you run this code:
#include <memory>
#include <iostream>
int main()
{
auto a = std::make_unique<char>(65);
std::cout << *a << "\n";
auto b = std::make_unique<char[]>(65);
std::cout << (int)b[0] << "\n";
}
It'll print A for the first one and an undefined value for the second one (possibly 0) as the array elements are uninitialised.
Your code "works" by chance, using any more than 1 element of your "array" will cause undefined behaviour.
When using an array non-template type parameter, it seems that size information is basically impossible to recover without passing it separately. For example, in a template
template<const char CStr[]>
struct ToTemp {
...
}
any references to sizeof(CStr) will return 8 (or 4, depending on your system), because it's actually a const char *. You can declare
template<const char CStr[5]>
struct ToTemp {
...
}
or
template<int N, const char CStr[N]>
struct ToTemp {
...
}
but the first one requires knowing the actual size when you're writing the class (not very useful), and the second one requires passing in the size separately anyway (not useful here -- could be useful for enforcing size constraints). Ideally I would have something like
template<const char CStr[int N]> //Let the compiler infer N based on the type
struct ToTemp {
...
}
or
template<int N = -1, const char CStr[N]> //Declare N but let it be forced to a given value, so that I don't have to pass it in
struct ToTemp {
...
}
... but of course neither of those work. In the end, I want to be able to write
const char foo[] = "abcd";
ToTemp<foo> bar;
and have bar correctly understand that sizeof(foo) is 5, without having to pass in a separate sizeof(foo) template argument.
You can use global string literals as a template parameter to match const char[] and calculate length via constexpr function:
constexpr size_t GetSize(const char str[])
{
for (size_t i = 0; ; ++i)
{
if (str[i] == '\0')
{
return i;
}
}
}
template <const char str[]>
struct X
{
constexpr static auto Size = GetSize(str);
};
constexpr const char string[] = "42";
void foo()
{
X<string> x;
static_assert(X<string>::Size == 2, "");
}
Here is my code:
#include <string.h>
#include <stdlib.h>
template <int ...I>
class MetaString
{
char buffer_[sizeof...(I)+1];
public:
// A constexpr constructor
constexpr MetaString(const char * arg) :buffer_{ encrypt(arg[I])... }
{}
constexpr const char *get()const { return buffer_; }
private:
constexpr char encrypt(const char c) const { return c ^ 0x55; }
};
char *decrypt(const char* buffer_, int size)
{
char* tmp = (char *)malloc(size + 1);
strcpy_s(tmp, size + 10, buffer_);
for (int i = 0; i < size; i++)
{
*(tmp + i) = *(tmp + i) ^ 0x55;
}
return tmp;
}
int main()
{
constexpr MetaString<0,1,2,3,5> var("Post Malone");
char * var1 = decrypt(var.get(), 5);
std::cout << var1 << std::endl;
return 1;
}
The idea is simple, I create object of MetaString and provide some string to it. The constructor encrypts the argument by XOR. Then I have decrypt function which decrypts value back.
The problem is that I set breakpoint in constructor (specifically this line constexpr MetaString(const char * arg) :buffer_{ encrypt(arg[I])... }) and it is hit when I run in debugging mode. Which as I understand means that the constructor is called during runtime.
To guarantee that functions be evaluated at compile time I created object this way constexpr MetaString<0,1,2,3,5> var("Post Malone"); But I've read that constexpr variable must be literal type.
So my question is how can I manage to have variable like var (which would have encrypted data in it and be evaluated at compilation time) and then call decrypt at runtime and get original value?
constexpr only guarantees that a function or variable can be used in a constant expression. It does not guarantee that a function/object is going to always be evaluated/constructed at compiletime. In your particular case, that's actually not really possible since we're talking about an object with automatic storage duration. The object, if it is going to be created, can only really be created when the program is running. Try making your variable static…
I have written some code to cast const char* to int by using constexpr and thus I can use a const char* as a template argument. Here is the code:
#include <iostream>
class conststr
{
public:
template<std::size_t N>
constexpr conststr(const char(&STR)[N])
:string(STR), size(N-1)
{}
constexpr conststr(const char* STR, std::size_t N)
:string(STR), size(N)
{}
constexpr char operator[](std::size_t n)
{
return n < size ? string[n] : 0;
}
constexpr std::size_t get_size()
{
return size;
}
constexpr const char* get_string()
{
return string;
}
//This method is related with Fowler–Noll–Vo hash function
constexpr unsigned hash(int n=0, unsigned h=2166136261)
{
return n == size ? h : hash(n+1,(h * 16777619) ^ (string[n]));
}
private:
const char* string;
std::size_t size;
};
// output function that requires a compile-time constant, for testing
template<int N> struct OUT
{
OUT() { std::cout << N << '\n'; }
};
int constexpr operator "" _const(const char* str, size_t sz)
{
return conststr(str,sz).hash();
}
int main()
{
OUT<"A dummy string"_const> out;
OUT<"A very long template parameter as a const char*"_const> out2;
}
In this example code, type of out is OUT<1494474505> and type of out2 is OUT<106227495>. Magic behind this code is conststr::hash() it is a constexpr recursion that uses FNV Hash function. And thus it creates an integral hash for const char* which is hopefully a unique one.
I have some questions about this method:
Is this a safe approach to use? Or can this approach be an evil in a specific use?
Can you write a better hash function that creates different integer for each string without being limited to a number of chars? (in my method, the length is long enough)
Can you write a code that implicitly casts const char* to int constexpr via conststr and thus we will not need aesthetically ugly (and also time consumer) _const user-defined string literal? For example OUT<"String"> will be legal (and cast "String" to integer).
Any help will be appreciated, thanks a lot.
Although your method is very interesting, it is not really a way to pass a string literal as a template argument. In fact, it is a generator of template argument based on string literal, which is not the same: you cannot retrieve string from hashed_string... It kinda defeats the whole interest of string literals in templates.
EDIT : the following was right when the hash used was the weighted sum of the letters, which is not the case after the edit of the OP.
You can also have problems with your hash function, as stated by mitchnull's answer. This may be another big problem with your method, the collisions. For example:
// Both outputs 3721
OUT<"0 silent"_const> out;
OUT<"7 listen"_const> out2;
As far as I know, you cannot pass a string literal in a template argument straightforwardly in the current standard. However, you can "fake" it. Here's what I use in general:
struct string_holder //
{ // All of this can be heavily optimized by
static const char* asString() // the compiler. It is also easy to generate
{ // with a macro.
return "Hello world!"; //
} //
}; //
Then, I pass the "fake string literal" via a type argument:
template<typename str>
struct out
{
out()
{
std::cout << str::asString() << "\n";
}
};
EDIT2: you said in the comments you used this to distinguish between several specializations of a class template. The method you showed is valid for that, but you can also use tags:
// tags
struct myTag {};
struct Long {};
struct Float {};
// class template
template<typename tag>
struct Integer
{
// ...
};
template<> struct Integer<Long> { /* ... */ };
// use
Integer<Long> ...; // those are 2
Integer<Float> ...; // different types
Here is the pattern that I am using for template const string parameters.
class F {
static constexpr const char conststr[]= "some const string";
TemplateObject<conststr> instance;
};
see :
https://stackoverflow.com/a/18031951/782168