Variant with variadic templates - c++

Sorry if this case is rather complicated, but I hope it helps people to better understanding modern c++ usage. So I want to make this code works. It should produce special lambdas for single integral type and for variant type for calculate sequence of terms on hard static cast to single type or on soft variant cast to common type, while this terms will be using. I add comments which describes what I really try to do in this code.
#include <variant>
#include <type_traits>
#include <string>
#include <functional>
#include <iostream>
#include <memory>
#include <optional>
#include <any>
#include <utility>
/* Visitor */
// Should get values from a variant
template <class... Ts>
struct Visitor;
template <class T, class... Ts>
struct Visitor<T, Ts...> : T, Visitor<Ts...> {
Visitor(T t, Ts... rest) : T(t), Visitor<Ts...>(rest...) {}
using T::operator();
using Visitor<Ts...>::operator();
};
template <class T>
struct Visitor<T> : T {
Visitor(T t) : T(t) {}
using T::operator();
};
/* Calculator */
// Should get special lambda for same type integrals and for variant packed integrals
template<class T, class... Ts>
class Calculator {
public:
// lambda for simple calculate same type integrals
static auto sum = [](T a, T b) { return a + b; };
// api for get current value of variant
template<typename... Vs>
static auto variant_value(std::variant<Vs...> v) {
return std::visit(Visitor<Vs...>{}, v);
}
// lambda for unpack variant arguments calc common value and pack in variant again
template<typename... Vs>
static auto variant_sum = [](std::variant<Vs...> a, std::variant<Vs...> b) {
auto value = variant_value<Vs...>(a) + variant_value<Vs...>(b);
return std::variant<Vs...>(value);
};
};
/* Term Producer */
namespace term::legion {
using std::function, std::any;
template<typename T>
function<any(any)> legion(auto& algebra) noexcept { // std::function<T(T,T...)
function<any(any)> redex = [](std::any a) {return a;};
// I delete code here because its not important now
return redex;
}
// production lamda for single type values
template<typename T>
std::function<std::any(std::any)> sum(T arg) noexcept {
return legion<T>(Calculator<T>::sum);
};
// production lambda for variant type values
template<typename ...Vs>
std::function<std::any(std::any)> sum() noexcept {
std::cout << "variant sum selected" << std::endl;
return legion<std::variant<Vs...>>(Calculator<Vs...>::template variant_sum<Vs...>);
};
}
int main() {
// term contains lambda for single type
auto sm = term::legion::sum<int>();
// term contains lambda for variant type
auto v_sm = term::legion::sum<char, int16_t, double>();
}

I don't see a way to make your code works...
Anyway, some problems/suggestions
maybe your Visitor works but you can make better using the classic way: variadic inheritance
template <typename ... Ts>
struct Visitor : public Ts...
{ using Ts::operator()...; };
and avoiding specialization and recursion
When you call
auto sm = term::legion::sum<int>();
you have, inside sum() (given that Vs... is int),
Calculator<int>::template variant_sum<int>
that call, inside variant_sum (given that Vs... is int),
variant_value<int>(a) + variant_value<int>(b);
that instantiate, inside variant_value<int>(a) (given that Vs... is int), a
Visitor<int>
The problem is that Visitor inherit from is template paramenters and a class can't inherit from int.
To make a visitor, you need functions that works with all types of the variant but you have to works a little; for example, you can write a sort of operator-wrapper as follows
template <typename T>
struct foo
{ void operator() (T const &) { } };
and a visitor as follows
template <typename ... Ts>
struct Visitor : public foo<Ts>...
{ using foo<Ts>::operator()...; };
This way Visitor<int> inherit from foo<int> (not from int) and foo<int> as a operator() accepting an int.
This works as visitor but you ask
variant_value<Vs...>(a) + variant_value<Vs...>(b);
for the contained value.
And here come the big problem: you can't have the value from std::visit.
Or better... from std::variant<int> (a variant with only a type), you can. You can modify foo<T> as follows
template <typename T>
struct foo
{ T operator() (T const & val) { return val; } };
and (with a couple of little other corrections) this call
auto sm = term::legion::sum<int>();
compile.
But the following sum()
auto v_sm = term::legion::sum<char, int16_t, double>();
because the resulting visitor (Visitor<char, std::int16_t, double>) contains three different operator() functions, returning three different types (char, std::int16_t and double).
But std::visit() must return a single type. Not different types according the type active in the variant.
So I suppose your code has to be completely rethinked.
Other little problems
the following declaration is good in C++20
template<typename T>
function<any(any)> legion(auto& algebra) noexcept
but in C++17 you can't use auto as placeholder for the type of an argument (except for generic lambdas); the correct C++17 way pass through an additional template parameter, so
template <typename T, typename U>
function<std::any(std::any)> legion (U & algebra) noexcept
Add constexpr for sum and variant_sum inside Calculator
static constexpr auto sum = ...
static constexpr auto variant_sum = ...
If Calculator has only public members, you make it a struct.

Related

How to limit parameter less template method to types of the own template class?

I have a template class that represents a special integer type.
A minimal implementation of this class could look like this:
template<typename T>
struct Int {
static_assert(std::is_integral_v<T>, "Requires integral type.");
using NT = T;
T v;
explicit constexpr Int(T v) noexcept : v{v} {}
template<typename U, std::enable_if_t<std::is_integral_v<U>, bool> = true>
constexpr auto cast() const noexcept -> Int<U> {
return Int<U>{static_cast<U>(v)};
}
template<typename U, typename U::NT = 0>
constexpr auto cast() const noexcept -> Int<typename U::NT> {
return Int<typename U::NT>{static_cast<typename U::NT>(v)};
}
};
There are a number of predefined type names for most common use-cases of the class:
using Int8 = Int<int8_t>;
using Int16 = Int<int16_t>;
using Int32 = Int<int32_t>;
using Int64 = Int<int64_t>;
The goal is to use the types of this class naturally, yet with a set of methods. One of these methods is a .cast<>() method to convert between the underlying integer types:
int main(int argc, const char *argv[]) {
auto a = Int32{10};
auto b = a.cast<int64_t>();
auto c = a.cast<Int64>();
}
To cover a wide range of uses, by the user and programatically in templates, the cast template argument shall allow the native type and also the template class as argument. Specifying int64_t, Int64 or therefore Int<int64_t> shall lead to the exact same result.
I would like to limit the second cast method to values of the Int template class.
The approach shown in the example, will work with any class that has a type definition called NT in its namespace. As in my library NT is commonly used in template classes, it does not limit the usage of the cast method enough for my liking.
The following example illustrates a case I would like to avoid:
struct Unrelated {
using NT = int32_t;
};
int main(int argc, const char *argv[]) {
auto a = Int32{10};
auto b = a.cast<Unrelated>(); // NO! is confusing, shouldn't work.
}
Is there a commonly used approach to "enable" a method only with template instances of the own class?
I am aware there are simple solutions in C++2x. Yet, I need a solution that is working with C++17.
The first cast method, accepting all integral types shall stay intact.
First a type trait from Igor Tandetnik (my own was uglier):
template<typename T> struct Int; // forward declaration
template <typename T> struct is_Int : std::false_type {};
template <typename T> struct is_Int<Int<T>> : std::true_type {};
template <typename T> inline constexpr bool is_Int_v = is_Int<T>::value;
Then you could define the class and its cast like so:
template<typename T>
struct Int {
static_assert(std::is_integral_v<T>); // no SFINAE needed so use static_assert
using NT = T;
T v;
explicit constexpr Int(T v) noexcept : v{v} {}
template<class U> // accept all, no SFINAE needed
constexpr auto cast() const noexcept {
// use static_assert instead
static_assert(std::is_integral_v<U> || is_Int_v<U>); // using the trait
// ...and constexpr-if:
if constexpr (std::is_integral_v<U>) return Int<U>{static_cast<U>(v)};
else return U{static_cast<typename U::NT>(v)};
}
};

Accepting N arguments converting into the same type

I'm currently trying to make a vector class in C++.
The class should have a constructor which accepts as many arguments as there are dimensions in the vector. The dimensionality is defined by a template when instantiating the vector.
All augments should be able to be converted into the same data type from which the vector originates (defined in the template to).
This is what I have written so far (I used many snippets from other questions here):
// this section is to create an typedef struct all_same which checks if all elements are of the same type
template<typename ...T> // head template
struct all_same : std::false_type { };
template<> // accept if no elements are present
struct all_same<> : std::true_type { };
template<typename T> // accept if only one element is present
struct all_same<T> : std::true_type { };
template<typename T, typename ...Ts> // check if first and second value are the same type and recurse
struct all_same<T, T, Ts...> : all_same<T, Ts...> { };
template<typename T, size_t N>
class vec_abs {
public:
vec_abs(const vec_abs &vec); // construct from another vector
explicit vec_abs(const std::array<T, N> &arr); // construct from array
template<typename ...Ts> requires // only compile if:
all_same<typename std::decay<Ts>::type...>::type // all are the same type (this might be optional, no sure)
&& std::conjunction<std::is_convertible<Ts, T>...>::value && // all can be converted to T
(sizeof(Ts) == N) // there are N arguments
explicit vec_abs(const Ts&&... values); // construct from multiple arguments
private:
std::array<T, N> data;
};
The fist section of the code tests if all arguments are of the same type, taken from this question.
I'm quite unsure about this solution (mainly because it's not working :D) and would appreciate any suggestions on improvements.
Thank you for your help!
If you do not want all arguments to be of same type you can remove that part. Apart from that you have a typo here:
(sizeof(Ts) == N)
should be
(sizeof...(Ts) == N)
After fixing that, forwarding the parameters and adding definition of the constructor, your code seems to do what you want:
#include <type_traits>
#include <array>
#include <iostream>
template<typename T, size_t N>
struct vec_abs {
template<typename ...Ts> requires // only compile if:
std::conjunction<std::is_convertible<Ts, T>...>::value && // all can be converted to T
(sizeof...(Ts) == N) // there are N arguments
explicit vec_abs(Ts&&... values) : data({std::forward<Ts>(values)...}) {}
std::array<T, N> data;
};
int main() {
auto foo = vec_abs<int,3>(1,2,3);
foo = vec_abs<int,3>(1.0,2,3);
for (const auto& e : foo.data) std::cout << e;
auto bar = vec_abs<std::string,3>("foo",std::string{"bar"},"moo");
for (const auto& e : bar.data) std::cout << e;
// bar = vec_abs<std::string,3>(123,1.2); // error wrong number
//bar = vec_abs<std::string,3>(123,1.2,42); // error cannot be converted
}
Output::
123foobarmoo
In case you actually do want the constraint that all parameters are of same type...
As the other answer mentions, the recursion in your all_same can be avoided. The following works already in C++11. Unfortunately I don't find the original source anymore.
template <typename T,typename...Ts>
struct all_same {
static const bool value = std::is_same< all_same, all_same<Ts...,T>>::value;
};
Recursive templates are very expensive (in terms of compile time and compiler memory-use) so while they work, and historically were the only way to do some solutions, more modern techniques are now available that are more succinct and compile much faster.
You can replace your entire all_same with a simple constexpr function using a fold expression:
template <typename T, typename... Ts>
constexpr bool all_same() {
return (std::is_same_v<T, Ts> && ...);
}
static_assert( all_same<int, int, int>() );
However, given that they all must be convertible to T, why do you also want the ensure they are the exact same type? That seems needlessly restrictive. You could easily change the function above to "all_convertible_to" using std::is_convertible_v<From, To> instead.

Problems wrapping a const-member-function in a functor

We implement a system that passes callbacks to object-instance member-functions. This works nicely, see the code below. The problem is that the current state of the implementation handles only non-const member functions.
The code below compiles and demonstrates that the system is working. As soon as the /* const */ is included, it no longer compiles.
The error messages are localized not English, but the first message is 'incomplete type'.
Logically, a call to a const member-function should be not more constrained than a call to a non-const member-function, so it seems that the basic goal is sensible.
It is clear that the type of a const-member differs from that of a non-const member. The problem is that we do not find a way to express to the compiler that the code is also valid for const members.
Where and how in the shown WrapP can we express that a const is acceptable? Is it possible to define a single template that accepts both, const and non-const, member functions?
#include <algorithm>
#include <functional>
#include <iostream>
using std::cout;
using std::endl;
template <auto F>
struct WrapP;
template <typename T, typename R, typename ... Args, R(T::* F)(Args...)>
struct WrapP<F> {
T* obj_;
WrapP(T* instance) : obj_(instance) {}
auto operator()(Args... args) const {
return (obj_->*F)(args...);
}
};
struct foo {
// Const below is needed, but could not be activated.
auto bar(double) /* const */ -> int {
return 314; };
};
int main() {
foo x;
// Create a functor for foo::bar
WrapP<&foo::bar> fp{ &x };
// Call the functor.
std::cout << fp( 3.14159265 ) << std::endl;
return 0;
}
If you want to specialize WrapP for a const member function, you need to specify that:
template <typename T, typename R, typename ... Args, R(T::* F)(Args...) const>
struct WrapP<F> { // ^___^
// ...
};
As far as I'm aware, there isn't a way to allow for either const or non-const member function pointers in a template parameter list, so you'll have to write separate specializations for those cases.
Do not specialize WrapP -- instead keep taking auto F as your template parameter, and then extract the information you need using something like Boost.CallableTraits or your own homegrown solution:
template <auto F>
struct WrapP {
using T = boost::callable_traits::class_of_t<decltype(F)>;
using R = boost::callable_traits::return_type_t<decltype(F)>;
T* obj_;
WrapP(T* instance) : obj_(instance) {}
template <typename... Args>
auto operator()(Args... args) const {
return (obj_->*F)(args...);
}
};
It is also possible to extract Args... but it's a bit more cumbersome as you get a std::tuple back.

How is nested template specialization done C++

I have a templated function defined as:
template<typename TObject> TObject Deserialize(long version, const Value &value)
what I need to do, is to write a specialization which would take vector defined as:
template<typename TNum, int cnt> class Vec
and still has access to cnt and TNum.
I have unsuccesfully tried
template<typename TNum, int cnt> Vec<TNum, cnt> Deserialize<Vec<TNum, cnt>>(long version, Value &value)
resulting in error: illegal use of explicit template arguments
What is the correct way to do it?
Usually, the correct answer to dealing with function templates and needing to partially specialize them, is to simply overload them instead. In this case this trick doesn't work directly because there are no arguments that depend on the template parameter, i.e. the template parameter is explicitly specified and not deduced. However, you can forward along to implementation functions, and make overloading work by using a simple tag struct.
#include <functional>
#include <iostream>
#include <type_traits>
#include <vector>
#include <array>
template <class T>
struct tag{};
template<typename TObject>
TObject Deserialize_impl(long version, tag<TObject>) {
std::cerr << "generic\n";
return {};
}
template<typename T, std::size_t N>
std::array<T,N> Deserialize_impl(long version, tag<std::array<T,N>>) {
std::cerr << "special\n";
return {};
}
template<typename TObject>
TObject Deserialize(long version) {
return Deserialize_impl(version, tag<TObject>{});
}
int main() {
Deserialize<int>(0);
Deserialize<std::array<int,3>>(0);
return 0;
}
Live example: http://coliru.stacked-crooked.com/a/9c4fa84d2686997a
I generally find these approaches strongly preferable to partial specialization of a struct with a static method (the other major approach here) as there are many things you can take advantage with functions, and it behaves more intuitively compared to specialization. YMMV.
While the functional tag-dispatch is a nice approach, here's a class specialization version for comparison. Both have their use, and I don't think either is an inherently regrettable decision but maybe one matches your personal style more.
For any class you write that needs a custom deserialize handler, just write a specialization of the Deserializer class:
#include <iostream>
#include <string>
using namespace std;
using Value = std::string;
// default deserialize function
template <typename TObject>
struct Deserializer {
static TObject deserialize(long version, const Value &value) {
std::cout << "default impl\n";
return TObject();
}
};
// free standing function (if you want it) to forward into the classes
template <typename TObject>
TObject deserialize(long version, const Value &value) {
return Deserializer<TObject>::deserialize(version, value);
}
// Stub example for your Vec class
template<typename TNum, int cnt> class Vec { };
// Stub example for your Vec deserializer specialization
template <typename TNum, int cnt> struct Deserializer<Vec<TNum, cnt>> {
static auto deserialize(long version, const Value &value) {
std::cout << "specialization impl: cnt=" << cnt << "\n";
return Vec<TNum, cnt>();
}
};
int main() {
Value value{"abcdefg"};
long version = 1;
deserialize<int>(version, value);
deserialize<Vec<int, 10>>(version, value);
}
Ideally in this situation, Vec should reflect its own template parameters as members Vec::value_type and Vec::size() which should be constexpr.
If the class fails to provide its own properties in its own interface, the next best thing is to define your own extension interface. In this situation, you can have separate metafunctions (like accessor functions), or a traits class (like a helper view class). I'd prefer the latter:
template< typename >
struct vector_traits;
template< typename TNum, int cnt >
struct vector_traits< Vec< TNum, cnt > > {
typedef TNum value_type;
constexpr static int size = cnt;
};
template<typename TVec> TVec Deserialize(long version, Value &value) {
typedef vector_traits< TVec > traits;
typedef typename traits::value_type TNum;
constexpr static int cnt = traits::size;
…
}
This solution fits into any existing function, and even makes the signatures cleaner. Also, the function is more flexible because you can adapt it by adding traits specializations instead of entire new overloads.

Template class with method depending on template parameter

I am writing a class designed to shoot random 3D vectors, but I use several geometric libraries in my projects (one included in the 3D simulation, one included in the analysis framework, one which is not included in a more-than-1-GB framework...). Each of these libraries has its own vector definition, with different names for the same method, such has getX(), GetX(), Get(0)... to get the first Cartesian coordinate. But sometimes a common naming convention has been adopted and some method names are the same across two or more libraries.
Of course I want to use this code for any of these vectors, so I implemented a template class. The problem is the following: how do I adapt my code to all these method names, without specializing my class for each implementation (some share the same method names) ?
I managed to write a class using a method or another, now I would like to generalize to any number of method. Something which says: "If you have method 1, use this implementation, if you have method 2, use this other one,... and if you have none, then compilation error".
Currently the class looks like (reduced to the part shooting a random direction):
// First some templates to test the presence of some methods
namespace detail_rand {
// test if a class contains the "setRThetaPhi" method
template<class T>
static auto test_setRThetaPhi(int) ->
decltype(void(std::declval<T>().setRThetaPhi(0.,0.,0.)),
std::true_type{});
template<class T>
static auto test_setRThetaPhi(float)->std::false_type;
}
// true_type if the class contains the "setRThetaPhi" method
template<class T>
struct has_setRThetaPhi : decltype(detail_rand::test_setRThetaPhi<T>(0)) {};
// The actual class
template<class vector>
class Random
{
// everything is static for easy use, might change later
private:
Random() = delete;
Random(Random&) = delete;
// the distribution, random generator and its seed
static decltype(std::chrono::high_resolution_clock::now().time_since_epoch().count()) theSeed;
static std::default_random_engine theGenerator;
static std::uniform_real_distribution<double> uniform_real_distro;
// Shoot a direction, the actual implementation is at the end of the file
private: // the different implementations
static const vector Dir_impl(std::true_type const &);
static const vector Dir_impl(std::false_type const &);
public: // the wrapper around the implementations
inline static const vector Direction() {
return Dir_impl(has_setRThetaPhi<vector>());
}
};
/// initialisation of members (static but template so in header)
// the seed is not of cryptographic quality but here it's not relevant
template<class vector>
decltype(std::chrono::high_resolution_clock::now().time_since_epoch().count())
Random<vector>::theSeed =
std::chrono::high_resolution_clock::now().time_since_epoch().count();
template<class vector>
std::default_random_engine Random<vector>::theGenerator(theSeed);
template<class vector>
std::uniform_real_distribution<double> Random<vector>::uniform_real_distro(0.,1.);
/// Implementation of method depending on the actual type of vector
// Here I use the "setRThetaPhi" method
template<class vector>
const vector Random<vector>::Dir_impl(std::true_type const &)
{
vector v;
v.setRThetaPhi(1.,
std::acos(1.-2.*uniform_real_distro(theGenerator)),
TwoPi()*uniform_real_distro(theGenerator));
return std::move(v);
}
// Here I use as a default the "SetMagThetaPhi" method
// but I would like to test before if I really have this method,
// and define a default implementation ending in a compilation error
// (through static_assert probably)
template<class vector>
const vector Random<vector>::Dir_impl(std::false_type const &)
{
vector v;
v.SetMagThetaPhi(1.,
std::acos(1.-2.*uniform_real_distro(theGenerator)),
TwoPi()*uniform_real_distro(theGenerator));
return std::move(v);
}
Something which says: "If you have method 1, use this implementation, if you have method 2, use this other one,... and if you have none, then compilation error".
I wrote an article that explains how to implement exactly what you need in C++11, C++14 and C++17: "checking expression validity in-place with C++17".
I will synthesize the C++11 and C++14 solutions below - you can use them to normalize all the interfaces you're dealing with by wrapping them inside a single "common" one. You can then implement your algorithms on the "common" interface.
Assume that you have:
struct Cat { void meow() const; };
struct Dog { void bark() const; };
And you want to create a function template make_noise(const T& x) that calls x.meow() if valid, otherwise x.bark() if valid, otherwise produces a compiler error.
In C++11, you can use enable_if and the detection idiom.
You will need to create a type trait for every member you wish to check the existence of. Example:
template <typename, typename = void>
struct has_meow : std::false_type { };
template <typename T>
struct has_meow<T, void_t<decltype(std::declval<T>().meow())>>
: std::true_type { };
Here's an usage example using enable_if and trailing return types - this technique makes use of expression SFINAE.
template <typename T>
auto make_noise(const T& x)
-> typename std::enable_if<has_meow<T>{}>::type
{
x.meow();
}
template <typename T>
auto make_noise(const T& x)
-> typename std::enable_if<has_bark<T>{}>::type
{
x.bark();
}
In C++14, you can use generic lambdas and an implementation of static_if (here's a talk I gave at CppCon 2016 about a possible one) to perform the check with an imperative-like syntax.
You need a few utilities:
// Type trait that checks if a particular function object can be
// called with a particular set of arguments.
template <typename, typename = void>
struct is_callable : std::false_type { };
template <typename TF, class... Ts>
struct is_callable<TF(Ts...),
void_t<decltype(std::declval<TF>()(std::declval<Ts>()...))>>
: std::true_type { };
// Wrapper around `is_callable`.
template <typename TF>
struct validity_checker
{
template <typename... Ts>
constexpr auto operator()(Ts&&...) const
{
return is_callable<TF(Ts...)>{};
}
};
// Creates `validity_checker` by deducing `TF`.
template <typename TF>
constexpr auto is_valid(TF)
{
return validity_checker<TF>{};
}
After that, you can perform all of your checks inside a single overload of make_noise:
template <typename T>
auto make_noise(const T& x)
{
auto has_meow = is_valid([](auto&& x) -> decltype(x.meow()){ });
auto has_bark = is_valid([](auto&& x) -> decltype(x.bark()){ });
static_if(has_meow(x))
.then([&x](auto)
{
x.meow();
})
.else_if(has_bark(x))
.then([&x](auto)
{
x.bark();
})
.else_([](auto)
{
// Produce a compiler-error.
struct cannot_meow_or_bark;
cannot_meow_or_bark{};
})(dummy{});
}
Some macro black magic and if constexpr allow you to write this in C++17:
template <typename T>
auto make_noise(const T& x)
{
if constexpr(IS_VALID(T)(_0.meow()))
{
x.meow();
}
else if constexpr(IS_VALID(T)(_0.bark()))
{
x.bark();
}
else
{
struct cannot_meow_or_bark;
cannot_meow_or_bark{};
}
}
You could solve this by introducing your own names for the operations. Do this by creating a trait class and specialising it for each of the libraries. Something like this:
template <class Vector>
struct VectorTraits;
template <>
struct VectorTraits<Lib1::Vector>
{
static auto getX(const Lib1::Vector &v) { return v.GetX(); }
// ... etc.
};
template <>
struct VectorTraits<Lib2::Vector>
{
static auto getX(const Lib2::Vector &v) { return v.Get(0); }
// ... etc.
};
//Usage:
template <class vector>
auto norm2(const vector &v)
{
using V = VectorTraits<vector>;
return V::getX(v) * V::getX(v) + V::getY(v) + V::getY(v);
}
If you want static assertions for the unsupported operations, you can put them into the unspecialised template:
template <class T>
struct False : std::false_type {};
template <class Vector>
struct VectorTraits
{
static void getX(const Vector &)
{
static_assert(False<Vector>::value, "This type does not support getting x");
}
};