constexpr with string operations workaround? - c++

This previously answered question explains why the code I have posted below does not work. I have a follow-up question: is there a workaround that is conceptually equivalent, i.e., achieves compile-time string concatenation, but is implemented in a way that is actually supported by C++11? Using std::string is completely non-essential.
constexpr std::string foo() { return std::string("foo"); }
constexpr std::string bar() { return std::string("bar"); }
constexpr std::string foobar() { return foo() + bar(); }

Compile-time "string" concatenation :
#include <iostream>
#include <string>
template <char ... CTail>
struct MetaString
{
static std::string string()
{
return std::string{CTail...};
}
};
template <class L, class R>
struct Concatenate;
template <char ... LC, char ... RC>
struct Concatenate<MetaString<LC ... >, MetaString<RC ... >>
{
typedef MetaString<LC ..., RC ... > Result;
};
int main()
{
typedef MetaString<'f', 'o', 'o'> Foo;
typedef MetaString<'b', 'a', 'r'> Bar;
typedef typename Concatenate<Foo, Bar>::Result FooBar;
std::cout << Foo::string() << std::endl; // foo
std::cout << Bar::string() << std::endl; // bar
std::cout << FooBar::string() << std::endl; // foobar
}

Sprout C++ Libraries provide constexpr string. see:
https://github.com/bolero-MURAKAMI/Sprout/blob/master/libs/string/test/string.cpp

Related

Template function deduction fail on std::conditional argument

Please, before marking this as a duplicate of This question read the entirety of the post
This piece of code fails to compile, with a template deduction error:
#include <iostream>
#include <type_traits>
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
template<typename TYPE>
void Bar(MyType<TYPE> Input)
{
std::cout << typeid(Input).name() << std::endl;
}
};
int main()
{
MyClass<float, 1> c;
c.Foo();
return 0;
}
I understand the point that was made in the question i linked above, which is that "the condition which allows to choose the type to be deduced depends on the type itself", however, why would the compiler fail in the specific case i provided as the condition here seems to be fully independent from the type, or is there something i'm missing?
I would be more than happy if someone could refer to a section of the c++ standard that would allow me to fully understand this behaviour.
As the linked question, TYPE is non deducible. MyType<TYPE> is actually XXX<TYPE>::type.
You have several alternatives, from your code, I would say one of
Bar no longer template:
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
void Bar(MyType<T> Input)
{
std::cout << typeid(Input).name() << std::endl;
}
};
requires (or SFINAE/specialization for pre-c++20):
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
template<typename TYPE>
void Bar(TYPE Input) requires(N > 0)
{
std::cout << typeid(Input).name() << std::endl;
}
void Bar(double Input) requires(N <= 0)
{
std::cout << typeid(Input).name() << std::endl;
}
};

type trait for function pointer?

I need to conditionally use either std::abs or std::fabs inside template class, here is relevant code in simplified version:
template <typename T>
class C
{
public:
using type = std::conditional_t<std::is_integral_v<T>, std::uint64_t, long double>;
using check = std::is_integral<type>;
// ERROR: mismatch in format parameter list
constexpr auto ptr_abs = check::value ? &std::abs<check::value_type> : &std::fabs;
// use pointer
void use_ptr()
{
auto x = (*ptr_abs)(-3);
}
};
None of the attempts worked for me, I'm clueless.
int main()
{
C<int> a;
a.f();
C<float> b;
b.f();
}
Do you really need to work with function pointers? Wouldn't be better to exploit C++ type-safe mechanisms? Such as follows:
template <typename T>
class C
{
public:
using type = std::conditional_t<std::is_integral_v<T>, std::uint64_t, long double>;
static const bool check = std::is_integral_v<type>;
std::function<type(type)> abs = [](auto arg)
{
if constexpr (check) return std::abs(static_cast<long long>(arg));
else return std::fabs(arg);
};
void use()
{
auto x = abs(-3);
}
};
This works for me well. Just note that there is no std::abs for unsigned integers, therefore, to avoid ambiguity, I had to choose a particular overload by casting (to long long in this example; I don't know what is Result).
Before C++17, where there is no if constexpr, you can achieve the same just with some more typing by using template specializations.
Resolve the function overload with the type of the pointer:
#include <cmath>
#include <type_traits>
#include <cstdlib>
#include <iostream>
template <typename T>
class C {
public:
static constexpr T (*ptr_abs)(T) = &std::abs;
void f() {
std::cout << typeid(ptr_abs).name() << "\n";
auto x = (*ptr_abs)(-3);
}
};
int main()
{
C<int> a;
a.f(); // PFiiE
C<float> b;
b.f(); // PFffE
C<double> c;
c.f(); // PFddE
}
Maybe I've misunderstood your problem, but it seems to me that you could separately define your version of abs that behaves as you want and then use it inside other classes
#include <cmath>
#include <cstdint>
#include <complex>
#include <iostream>
#include <limits>
#include <type_traits>
#include <typeinfo>
namespace my {
template <class T>
auto abs_(T x)
{
if constexpr ( std::is_unsigned_v<T> ) {
return static_cast<uintmax_t>(x);
}
else if constexpr ( std::is_integral_v<T> ) {
return static_cast<uintmax_t>(std::abs(static_cast<intmax_t>(x)));
}
else {
return std::fabs(static_cast<long double>(x));
}
}
template <class T>
auto abs_(std::complex<T> const& x)
{
return std::abs(static_cast<std::complex<long double>>(x));
}
}
template <typename T>
class C
{
public:
void use(T x)
{
std::cout << typeid(T).name() << ' ' << x;
auto a = my::abs_(x);
std::cout << ' ' << typeid(a).name() << ' ' << a << '\n';
}
};
int main()
{
C<int> a;
a.use(-42);
C<float> b;
b.use(-0.1);
C<long long> c;
c.use(std::numeric_limits<long long>::min());
C<size_t> d;
d.use(-1);
C<std::complex<double>> e;
e.use({-1, 1});
}
Testable here.

std::variant reflection. How can I tell which type of value std::variant is assigned?

I have a class called foo_t that has a member called bar which could be any one of the types std::string, int, std::vector<double>, etc. I would like to be able to ask foo_t which type bar has been assigned to. I decided to use std::variant.
I've written a solution, but I'm not sure if this is a good use of std::variant. I'm not sure if it matters, but I expect the list of types to possibly grow much bigger in the future. I made an enum class to store which type std::variant is assigned to. My first implementation also available on wandbox:
#include <iostream>
#include <variant>
#include <vector>
#include <string>
enum foo_kind_t {
double_list,
name_tag,
number,
unknown
};
template <typename val_t>
struct get_foo_kind_t {
constexpr static foo_kind_t value = unknown;
};
template <>
struct get_foo_kind_t<int> {
constexpr static foo_kind_t value = number;
};
template <>
struct get_foo_kind_t<std::string> {
constexpr static foo_kind_t value = name_tag;
};
template <>
struct get_foo_kind_t<std::vector<double>> {
constexpr static foo_kind_t value = double_list;
};
class foo_t {
public:
foo_t(): kind(unknown) {}
template <typename val_t>
void assign_bar(const val_t &val) {
static_assert(get_foo_kind_t<val_t>::value != unknown, "unsupported assignment");
kind = get_foo_kind_t<val_t>::value;
bar = val;
}
foo_kind_t get_kind() {
return kind;
}
template <typename val_t>
val_t get_bar() {
if (get_foo_kind_t<val_t>::value != kind) {
throw std::runtime_error("wrong kind");
}
return std::get<val_t>(bar);
}
private:
foo_kind_t kind;
std::variant<
int,
std::string,
std::vector<double>
> bar;
};
template <typename val_t>
void print_foo(foo_t &foo) {
std::cout << "kind: " << foo.get_kind() << std::endl;
std::cout << "value: " << foo.get_bar<val_t>() << std::endl << std::endl;
}
int main(int, char*[]) {
// double_list
foo_t b;
std::vector<double> b_val({ 1.0, 1.1, 1.2 });
b.assign_bar(b_val);
std::cout << "kind: " << b.get_kind() << std::endl;
std::cout << "value: vector size: " << b.get_bar<std::vector<double>>().size() << std::endl << std::endl;
// name_tag
foo_t d;
std::string d_val("name");
d.assign_bar(d_val);
print_foo<std::string>(d);
// number
foo_t c;
int c_val = 99;
c.assign_bar(c_val);
print_foo<int>(c);
// unknown
foo_t a;
std::cout << a.get_kind() << std::endl;
return 0;
}
Is this a good way to do it? Is there a way having better performance? Is there a way that requires less code to be written? Is there a way that doesn't require C++17?
If you only need to ask "Is this variant of type X ?" for a single type X, then I recommend that you prefer std::holds_alternative over std::variant::index because the line of code is easier to read and will not have to be updated if the index of the type in the variant changes in the future.
Example:
if (std::holds_alternative<X>(my_variant)) {
std::cout << "Variant is of type X" << std::endl;
}
Using std::variant::index to check stored type at runtime.
There is a solution with type traits
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
using MyVariant = std::variant<int, std::string>;
enum class MyVariantType { integer, string };
template <MyVariantType Type, typename T> struct is_variant_type : std::false_type {};
template <> struct is_variant_type<MyVariantType::integer, int > : std::true_type {};
template <> struct is_variant_type<MyVariantType::string , std::string> : std::true_type {};
template<MyVariantType VT>
bool check_variant_type(const MyVariant& myvar)
{
return std::visit([&](const auto& arg) {
return is_variant_type<VT, std::decay_t<decltype(arg)>>::value;
}, myvar);
}
int main(int argc, char* argv[])
{
MyVariant a = int(10);
MyVariant b = "Hello";
std::cout << check_variant_type<MyVariantType::integer>(a);
std::cout << check_variant_type<MyVariantType::integer>(b);
std::cout << check_variant_type<MyVariantType::string>(a);
std::cout << check_variant_type<MyVariantType::string>(b);
return 0;
}

Templated snprintf

I need to convert some numbers (integers and doubles) into std::strings, and for performance reasons cannot use stringstream (we found it to be very slow when used concurrently)
It would be nice to be able to do something like
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
// next line is a bit pseduo-y
snprintf(res, sizeof(res), "%T", number);
return string(res);
}
But I'm not really sure how is the best way to achieve this?
Here's one idea. Use:
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
snprintf(res, sizeof(res), getPrintfFormat<T>(), number);
return res;
}
Sample program:
#include <iostream>
#include <cstdio>
#include <string>
template <typename T> struct PrintfFormat;
template <> struct PrintfFormat<int>
{
static char const* get() { return "%d"; }
};
template <> struct PrintfFormat<float>
{
static char const* get() { return "%f"; }
};
template <> struct PrintfFormat<double>
{
static char const* get() { return "%f"; }
};
template <typename T>
char const* getPrintfFormat()
{
return PrintfFormat<T>::get();
}
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
snprintf(res, sizeof(res), getPrintfFormat<T>(), number);
return res;
}
int main()
{
std::cout << numberToString(10) << std::endl;
std::cout << numberToString(10.2f) << std::endl;
std::cout << numberToString(23.456) << std::endl;
}
Output:
10
10.200000
23.456000
It also provides a level of type safety. With the posted code, using
std::cout << numberToString('A') << std::endl;
will result in a compile time error.

how to generate code to initialize a std::vector with a custom Zero value if it exists as T::Zero?

BACKGROUND
I have a container class that has a std::vector<T> member that I initialize with the constructor that takes size_t n_items. I would like to initialize that vector with my own Zero() function which returns 0; by default, but if static member T::Zero exists I want to return that instead.
In my first attempt, I use expression SFINAE, but that failed due to ambiguous overload since both the generic version of Zero and the Zero have the same signature with no arguments. So now, I'm trying to convert the code into classes with operator().
I think I need to use std::enable_if somehow, but I'm not sure how to go about coding this.
FAILED ATTEMPT
#include <cassert>
#include <iostream>
#include <vector>
template<typename T>
struct Zero
{
T operator() const { return 0; }
};
template<typename T>
struct Zero
{
auto operator() const ->
decltype( T::Zero )
{
return T::Zero;
}
};
struct Foo
{
char m_c;
static Foo Zero;
Foo() : m_c( 'a' ) { }
Foo( char c ) : m_c( c ) { }
bool operator==( Foo const& rhs ) const { return m_c==rhs.m_c; }
friend std::ostream& operator<<( std::ostream& os, Foo const& rhs )
{
os << (char)(rhs.m_c);
return os;
}
};
Foo Foo::Zero( 'z' );
int
main( int argc, char** argv )
{
std::vector<unsigned> v( 5, Zero<unsigned>() );
std::vector<Foo> w( 3, Zero<Foo>() );
for( auto& x : v )
std::cout << x << "\n";
std::cout << "---------------------------------\n";
for( auto& x : w )
{
assert( x==Foo::Zero );
std::cout << x << "\n";
}
std::cout << "ZERO = " << Foo::Zero << "\n";
return 0;
}
#include <string>
#include <iostream>
#include <vector>
#include <type_traits>
namespace detail
{
template<class T, class = decltype(T::zero)>
std::true_type has_zero_impl(int);
template<class T>
std::false_type has_zero_impl(short);
}
template<class T>
using has_zero = decltype(detail::has_zero_impl<T>(0));
template<class T, class = has_zero<T>>
struct zero
{
constexpr static T get() { return T(); }
};
template<class T>
struct zero<T, std::true_type>
{
constexpr static auto get() -> decltype(T::zero)
{ return T::zero; }
};
Usage example:
template<>
struct zero<std::string>
{
static constexpr const char* get()
{ return "[Empty]"; }
};
struct foo
{
int m;
static constexpr int zero = 42;
};
int main()
{
std::cout << zero<int>::get() << "\n";
std::cout << zero<std::string>::get() << "\n";
std::cout << zero<foo>::get() << "\n";
}
Compact version w/o trait:
template<class T>
struct zero
{
private:
template<class X>
constexpr static decltype(X::zero) zero_impl(int)
{ return X::zero; }
template<class X>
constexpr static X zero_impl(short)
{ return X(); }
public:
constexpr static auto get()
-> decltype(zero_impl<T>(0))
{
return zero_impl<T>(0);
}
};
template<>
struct zero<std::string>
{
constexpr static const char* get()
{ return "[Empty]"; }
};
Maybe:
#include <iostream>
#include <vector>
template <typename T>
inline T zero() {
return T();
}
template <>
inline std::string zero<std::string>() {
return "[Empty]";
}
int main() {
std::vector<std::string> v(1, zero<std::string>());
std::cout << v[0] << '\n';
}
I have a half good news: I found a very simple way (leveraging SFINAE), however the output is not exactly what I expected :)
#include <iostream>
#include <string>
#include <vector>
// Meat
template <typename T, typename = decltype(T::Zero)>
auto zero_init_impl(int) -> T { return T::Zero; }
template <typename T>
auto zero_init_impl(...) -> T { return T{}; }
template <typename T>
auto zero_init() -> T { return zero_init_impl<T>(0); }
// Example
struct Special { static Special const Zero; std::string data; };
Special const Special::Zero = { "Empty" };
int main() {
std::vector<int> const v{3, zero_init<int>()};
std::vector<Special> const v2{3, zero_init<Special>()};
std::cout << v[0] << ", " << v[1] << ", " << v[2] << "\n";
std::cout << v2[0].data << ", " << v2[1].data << ", " << v2[2].data << "\n";
return 0;
}
As mentioned, the result is surprising was explained by dyp, we have to be careful not use std::initializer<int> by mistake and then read past the end:
3, 0, 0
Empty, Empty, Empty
Curly brace initialization yields a different result than regular brace initialization (see here) which gives the expected 0, 0, 0. So you have to use regular braces.