Stringify template parameters - c++

I am trying to extend the code from the answer to this question Unpack parameter pack into string view.
Instead of stringifying char-only types, I would like to use a constexpr_string type, custom written:
#include <array>
#include <iostream>
class constexpr_string {
public:
template <std::size_t N>
constexpr constexpr_string(const char (&s)[N]) : string_{s}, size_{N - 1} {}
constexpr constexpr_string() = default;
constexpr char const operator[](std::size_t n) const { return string_[n]; }
constexpr std::size_t GetSize() { return size_; }
private:
char const *string_{nullptr};
std::size_t size_{0};
};
template <constexpr_string... strings> constexpr auto stringify() {
std::array<constexpr_string, sizeof...(strings)> array = {strings...};
return array;
}
int main() {
static constexpr auto s = stringify<"abc", "def", "fgh">();
for (auto &i : s) {
std::cout << i << std::endl;
}
return 0;
}
When I compile though, I get :
main.cpp:18:31: error: ‘class constexpr_string’ is not a valid type for a template non-type parameter
template constexpr auto stringify()
Is such a thing even possible? I'm compiling with g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0. Many thanks in advance!

Related

Template specialization for class wrappers

I can't have my int class wrapper acting like a primitive int in template specialization.
I've prepared this code to explain my issue in detail:
#include <iostream>
#include <stdlib.h>
class Integer
{
int _v;
public:
constexpr explicit Integer(int v) : _v(v) {}
constexpr Integer next() const { return Integer(_v + 1); }
constexpr operator int() const { return _v;}
};
static constexpr auto integer1 = Integer(1);
static constexpr auto integer2a = Integer(2);
static constexpr auto integer2b = integer1.next();
template <const Integer& i>
void foo_Integer()
{
static auto foo_id = rand();
std::cout << foo_id << std::endl;
}
static constexpr auto int1 = 1;
static constexpr auto int2a = 2;
static constexpr auto int2b = int1 + 1;
template <int i>
void foo_int()
{
static auto foo_id = rand();
std::cout << foo_id << std::endl;
}
int main()
{
foo_int<int1>();
foo_int<int2a>();
foo_int<int2b>(); // same template specialization as above -> :)
foo_Integer<integer1>();
foo_Integer<integer2a>();
foo_Integer<integer2b>(); // different template specialization -> :(
}
As you can see running the code
foo_int<int2a>();
foo_int<int2b>();
use the same template specialization, while
foo_Integer<integer2a>();
foo_Integer<integer2b>();
use different template specializations.
This is, of course, correct, from the compiler point of view, since the template accepts a const Integer&, but I hope there are other better approaches to workaround the issue.
You can easily make Integer a structural type (C++20). Then its values are valid template parameters.
class Integer
{
public:
int _v;
constexpr explicit Integer(int v) : _v(v) {}
constexpr Integer next() const { return Integer(_v + 1); }
constexpr operator int() const { return _v;}
};
template <Integer i>
void foo_Integer()
{
static auto foo_id = rand();
std::cout << foo_id << std::endl;
}
Live
And the values would be equivalent, even if they come from objects with different identities.

can I deduce a tuple element type in a function parameter (ie with std::tuple_element)?

I have a struct which stores some data in a tuple. I want to build a function getWithDefault<n>(m), which gets the data from the nth term but replaces it with m if the value is 0. But to do this, I have to know the correct data type for m in the function parameter: getWithDefault<>(WhichType?). Is there any way of doing this? I've tried with std::tuple_element, but it doesn't seem to work.
#include <iostream>
#include <tuple>
template <typename... T>
struct C
{
C(T... args) : t(std::make_tuple(args...)) {}
template <int n>
auto get() const
{ return std::get<n>(t); }
template <int n>
auto getWithDefault(std::tuple_element<n, decltype(t)>::type de) // Compiler error: identifier not found
{
const auto v = get<n>();
return v != 0 ? v : de;
}
private:
const std::tuple<T...> t;
};
int main()
{
C<int, int> c(0, 4);
std::cout << c.getWithDefault<0>(5); // this should return 5
return 0;
}
I can see why this code fails--std::tuple_element doesn't have access to the member variable from inside the function parameter. So, is there a viable way of deducing the type of a tuple term from within a function parameter?
There is no need to deduce the type, because you already know it. Maybe you refer to using decltype, but you also do not need that (you can, but need not). Anyhow...
For convenience you can use an alias template:
template <size_t n>
using nth_type = typename std::tuple_element<n,std::tuple<T...>>::type;
Full example:
#include <iostream>
#include <tuple>
template <typename... T>
struct C
{
C(T... args) : t(std::make_tuple(args...)) {}
template <size_t n>
using nth_type = typename std::tuple_element<n,std::tuple<T...>>::type;
template <int n>
auto get() const
{ return std::get<n>(t); }
template <size_t n>
auto getWithDefault(nth_type<n> de)
{
const auto v = get<n>();
return v != 0 ? v : de;
}
private:
const std::tuple<T...> t;
};
int main()
{
C<int, int> c(0, 4);
std::cout << c.getWithDefault<0>(5); // this should return 5
return 0;
}
You just have order of declaration issue (and a missing typename), move t before getWithDefault:
template <typename... T>
struct C
{
private:
const std::tuple<T...> t;
public:
C(T... args) : t(std::make_tuple(args...)) {}
template <int n>
auto get() const
{ return std::get<n>(t); }
template <int n>
auto getWithDefault(std::tuple_element_t<n, decltype(t)> de)
{
const auto v = get<n>();
return v != 0 ? v : de;
}
};
Demo

Function template argument deduction with user-defined conversion operator

Let's say I have a class that wraps a string literal:
template <size_t N>
class literal {
public:
constexpr literal(const char(&s)[N+1]) : wrapped_(s) {}
constexpr const char * c_str() const { return wrapped_; }
constexpr size_t size() const { return N; }
private:
const char (&wrapped_)[N+1];
};
template <size_t N>
literal<N-1> make_literal(const char (&s)[N]) { return literal<N-1>(s); }
Now, I'd like for instances of this wrapped string type to be convertible back to a const char[N] implicitly, in a way I can still access its size. I'd like to be able to do something like:
template <size_t N>
void foo(const char(&s)[N]) {
std::cout << N << ": " << s << std::endl;
}
int main() {
constexpr auto s = make_literal("testing");
foo(s);
}
My goal is to have one function defined for foo() that can accept actual string literals as well as wrapped literals. I've tried adding a user-defined conversion operator to the class definition:
using arr_t = char[N+1];
constexpr operator const arr_t&() const { return wrapped_; }
But this gives me the following with clang:
candidate template ignored: could not match 'const char [N]' against 'const literal<7>'
If I change the call to foo() to the following, it works:
foo((const char(&)[8])s);
...which means that the conversion operator works, but not in the context of template argument deduction. Is there any way I can make this work without defining foo() specifically to take a wrapped literal?
The problem you are having is templates never do conversions of the parameters. Since you give it a const literal<7>, that is all it has to work with.
The easy fix for this is to add an overload and then do the cast in the overload to call your string literal version. That should look like
template <size_t N>
void foo(const literal<N> &lit) {
foo(static_cast<typename literal<N>::arr_t&>(lit)); // explicitly cast to the array type alias
}
which gives you a full example of
template <size_t N>
class literal {
public:
constexpr literal(const char(&s)[N+1]) : wrapped_(s) {}
constexpr const char * c_str() const { return wrapped_; }
constexpr size_t size() const { return N; }
using arr_t = const char[N+1]; // <- Add const here since literals are const char[N]
constexpr operator const arr_t&() const { return wrapped_; }
private:
const char (&wrapped_)[N+1];
};
template <size_t N>
constexpr literal<N-1> make_literal(const char (&s)[N]) { return literal<N-1>(s); }
template <size_t N>
void foo(const char(&s)[N]) {
std::cout << N << ": " << s << std::endl;
}
template <size_t N>
void foo(const literal<N> &lit) {
foo(static_cast<typename literal<N>::arr_t&>(lit)); // explicitly cast to the array type alias
}
int main() {
constexpr auto s = make_literal("testing");
foo(s);
}
Yes, you are adding an overload but all of the important code does not have to be duplicated.
If you can use C++17 and you don't mind a little indirection you could do all of this with one function using a std::string_view and providing literal with a operator std::string_view. That would look like
template <size_t N>
class literal {
public:
constexpr literal(const char(&s)[N+1]) : wrapped_(s) {}
constexpr const char * c_str() const { return wrapped_; }
constexpr size_t size() const { return N; }
using arr_t = const char[N+1];
constexpr operator std::string_view() const { return wrapped_; }
private:
const char (&wrapped_)[N+1];
};
template <size_t N>
constexpr literal<N-1> make_literal(const char (&s)[N]) { return literal<N-1>(s); }
void foo(std::string_view s) {
std::cout << s.size() << ": " << s << std::endl;
}
int main() {
constexpr auto s = make_literal("testing");
foo(s);
foo("testing");
}

how to initialize a static constexpr member of std::vector<std::string> in c++11?

I'm trying to initialize a static constexpr std::vector of std::strings inside my class Foo. I will later use the address of its elements.
class Foo {
public:
static constexpr std::vector<std::string> a = {"a", "bc", "232"}; // not working, constexpr variable not literal ....
const std::vector<std::string> a = {"a", "bc", "232"}; // this works
}
using c++11, thanks.
I can live with const instead of constexpr. but it's a little bit odd that there's no way to do this
It's good you can live with const but, just for fun, I show you a way to make a better-than-nothing constexpr static member that uses std::array instead of std::vector and (again) std::array instead of std::string.
Unfortunately you're using C++11, so no std::index_sequence/std::make_index_sequence (available starting from C++14) but I add a C++11 substitute in the following full example.
If you know a superior limit for the length of the strings you want use in the constexpr member, say 9 (3 in you example), you can define a fakeString type as follows
using fakeString = std::array<char, 10u>;
Observe that the size of the std::array is max-length plus one (plus the final zero).
Now you can define foo as follows
struct foo
{
static constexpr std::array<fakeString, 3u> a
{{ fs("a"), fs("bc"), fs("232") }};
};
constexpr std::array<fakeString, 3u> foo::a;
where fs() is a constexpr function that return a fakeString given a C-style array of char and uses a fsh() helper functions
The fs() and fsh() functions are as follows
template <std::size_t ... Is, std::size_t N>
constexpr fakeString fsh (indexSequence<Is...> const &, char const (&s)[N])
{ return {{ s[Is]... }}; }
template <std::size_t N>
constexpr fakeString fs (char const (&s)[N])
{ return fsh(makeIndexSequence<N>{}, s); }
Now you can use foo::a as follows
for ( auto const & fakeS : foo::a )
std::cout << fakeS.data() << std::endl;
Observe that you have to call the data() method that return a char *, that is a C-style string.
I repeat: just for fun.
The following is a full compiling C++11 example
#include <array>
#include <iostream>
template <std::size_t...>
struct indexSequence
{ using type = indexSequence; };
template <typename, typename>
struct concatSequences;
template <std::size_t... S1, std::size_t... S2>
struct concatSequences<indexSequence<S1...>, indexSequence<S2...>>
: public indexSequence<S1..., ( sizeof...(S1) + S2 )...>
{ };
template <std::size_t N>
struct makeIndexSequenceH
: public concatSequences<
typename makeIndexSequenceH<(N>>1)>::type,
typename makeIndexSequenceH<N-(N>>1)>::type>::type
{ };
template<>
struct makeIndexSequenceH<0> : public indexSequence<>
{ };
template<>
struct makeIndexSequenceH<1> : public indexSequence<0>
{ };
template <std::size_t N>
using makeIndexSequence = typename makeIndexSequenceH<N>::type;
using fakeString = std::array<char, 10u>;
template <std::size_t ... Is, std::size_t N>
constexpr fakeString fsh (indexSequence<Is...> const &, char const (&s)[N])
{ return {{ s[Is]... }}; }
template <std::size_t N>
constexpr fakeString fs (char const (&s)[N])
{ return fsh(makeIndexSequence<N>{}, s); }
struct foo
{
static constexpr std::array<fakeString, 3u> a
{{ fs("a"), fs("bc"), fs("232") }};
};
constexpr std::array<fakeString, 3u> foo::a;
int main ()
{
for ( auto const & fakeS : foo::a )
std::cout << fakeS.data() << std::endl;
}

var used in its own initializer

The following code :
auto getConnection(const std::string &name) {
constexpr const std::size_t id{findFactoryId(_factories, name)};
const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second;
for (auto &connection : _connections[id])
if (connection.first) {
connection.first = false;
decltype(factory()) &res = std::experimental::any_cast(connection.second);
return res;
}
_connections[id].emplace_back(std::make_pair<bool, std::experimental::any>(false, factory()));
decltype(factory()) &res = std::experimental::any_cast(_connections[id].back().second);
return res;
}
compile with clang++, but with g++ gives this error:
In file included from main.cpp:2:0:
src/core/include/connectionpool.h: Dans la fonction membre « auto Core::ConnectionPool<Connectors>::getConnection(const string&) »:
src/core/include/connectionpool.h:28:79: erreur : the value of « id » is not usable in a constant expression
const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second;
^~
src/core/include/connectionpool.h:27:41: note : « id » used in its own initializer
constexpr const std::size_t id{findFactoryId(_factories, name)};
^~
src/core/include/connectionpool.h:28:81: erreur : the value of « id » is not usable in a constant expression
const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second;
^
src/core/include/connectionpool.h:27:41: note : « id » used in its own initializer
constexpr const std::size_t id{findFactoryId(_factories, name)};
^~
src/core/include/connectionpool.h:28:81: note : in template argument for type « unsigned int »
const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second;
^
I'm using those command to compile:
(clan)g++ -std=c++14 -O2 -Wall -pedantic -Wextra main.cpp
with g++ v6.3.1 and clang++ v3.9.1
The only link that look like to correspond to my issue is a bug report for gcc4.9 (which is solved) : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59937.
A minimal working example is available here.
From what I've understood of gcc error message, I should not have any error: id isn't used to initialise itself.
Should this code yield an error or not ?
If it should raise an error, what could I do to solve the error ?
Thank you for your answers.
The complete code:
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <functional>
#include <utility>
#include <type_traits>
#include <tuple>
#include <experimental/any>
template <class F, class... Ts>
constexpr void for_each_in_tuple(const std::tuple<Ts...> &tuple, F f) {
for_each_in_tuple(tuple, f, std::make_index_sequence<sizeof...(Ts)>());
}
template <class F, class... Ts, std::size_t... Is>
constexpr void for_each_in_tuple(const std::tuple<Ts...> &tuple, F f, std::index_sequence<Is...>) {
using expander = int[];
(void) expander{0, ((void)f(Is, std::get<Is>(tuple)), 0)...};
}
template <typename... Connectors>
class ConnectionPool {
public:
auto getConnection(const std::string &name) {
constexpr const std::size_t id{findFactoryId(_factories, name)};
const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second;
return factory();
}
private:
struct foo {
constexpr foo(std::size_t &i, const std::string &name) : i(i), name(name) {}
template <class T>
constexpr void operator()(const std::size_t is, const T pair) {
i = name == pair.first ? is : i;
}
std::size_t &i;
const std::string &name;
};
template <class Tuple>
static constexpr std::size_t findFactoryId(Tuple &tup, const std::string &name) {
std::size_t i = 0;
for_each_in_tuple(tup, foo(i, name));
return i;
}
std::tuple<std::pair<std::string, std::function<Connectors()>>...> _factories;
};
int main()
{
return 0;
}
EDIT
Change link to minimal working example: a function was missing.
EDIT 2
Add minimal working example in the post
The problem is on this line:
constexpr const std::size_t id{findFactoryId(_factories, name)};
The initializer of a constexpr variable must be a constant expression. In a constant expression you can not use the this pointer. You are implicitly using the this pointer by referring to _factories, which is a data member.
N4296 [expr.const] ¶2
A conditional-expression e is a core constant expression unless the evaluation of e... would evaluate one of the following expressions:
this, except in a constexpr function or a constexpr constructor that is being evaluated as part of e;
...
Surprisingly, both compilers are happy if we simply use an explicit this:
constexpr const std::size_t id{findFactoryId(this->_factories, name)};
But I do not believe that is conformant. Here is a portable workaround:
const auto _this = this;
constexpr const std::size_t id{findFactoryId(_this->_factories, name)};