Anyway to link mutiple if conditions toghether with c++ template? - c++

What I want is
template<typename T>
bool larger(T a, T b){
if(a.x>b.x&&a.y>b.y&&a.z>b.z) return true;
return false;
}
.
But , each T may only have some of the x,y,z values, for example
struct Txy{
double x,y;
}
So for Txy I would only judge by x and y.
I know I could specify the template to do so, but with many Ts there's no difference between write a function for each T...
Is there any better way to deal with this problem?

You say you can not modify the structs... but are they raw structs or do they have constructors?
If they are raw structs, what you can do is to use the numero uno solution for everything in computers: add one extra layer of indirection.
Instead of having larger compare the Ts directly and have to overload or specialize each one, have a new larger2 that compares "completed" versions of the structs, where the completed version is computed more or less generically:
// Your original one, won't work
template<typename T>
bool larger(T a, T b){
if(a.x>b.x&&a.y>b.y&&a.z>b.z) return true;
return false;
}
struct Txy {
int x, y;
};
struct Txz {
int x, z;
};
struct Txyz {
int x, y, z;
};
// This struct "completizes" Ts, adding manually the missing members.
// Note for this to work, we are forced to add constructors to Completizer
// (unless I am missing something)
template <typename T>
struct Completizer: T {
// this constructor is needed
Completizer (T const& t): T(t) {}
};
template<> struct Completizer<Txy>: Txy {
int z;
Completizer (Txy const& t): Txy(t), z(0) {}
};
template<> struct Completizer<Txz>: Txz {
int y;
Completizer (Txz const& t): Txz(t), y(0) {}
};
// this is the thing that actually does the magic
template<typename T>
bool larger2_impl(Completizer<T> const& a, Completizer<T> const& b) {
if(a.x>b.x&&a.y>b.y&&a.z>b.z) return true;
return false;
}
// the trick here is to have our "larger" function not compare the Ts directly,
// but do so by means of Completizer<T>
template<typename T>
bool larger2(T const& a, T const& b) {
return larger2_impl(Completizer<T>(a), Completizer<T>(b));
}
int main () {
Txy xy1 = {1, 2}, xy2 = {2, 3};
Txz xz1 = {1, 2}, xz2 = {2, 3};
Txyz xyz1 = {1, 2, 3}, xyz2 = {2, 3, 4};
// only here to avoid warnings
(void)xy1; (void)xy2;
(void)xz1; (void)xz2;
//larger(xy1, xy2); // does not compile
larger2(xyz1, xyz2); // compiles
larger2(xy1, xy2); // compiles
larger2(xz1, xz2); // compiles
}
The advantage of this method is that it scales somewhat easier if you start adding more members, since you can derive Completizer<Txyzw> from Completizer<Txyz>.

#include <iostream>
template <typename T, typename = void> struct has_member_x : std::false_type{};
template <typename T> struct has_member_x<T, decltype((void)T::x, void())> : std::true_type {};
template <typename T, typename = void> struct has_member_y : std::false_type{};
template <typename T> struct has_member_y<T, decltype((void)T::y, void())> : std::true_type {};
template <typename T, typename = void> struct has_member_z : std::false_type{};
template <typename T> struct has_member_z<T, decltype((void)T::z, void())> : std::true_type {};
struct Txy {
int x, y;
};
struct Txz {
int x, z;
};
template<typename T>
bool larger(T a, T b){
if constexpr (has_member_x<T>::value)
if (a.x <= b.x)
return false;
if constexpr (has_member_y<T>::value)
if (a.y <= b.y)
return false;
if constexpr (has_member_z<T>::value)
if (a.z <= b.z)
return false;
return true;
}
int main() {
std:: cout << larger(Txy{1,2}, Txy{2,3}) << "\n";
std:: cout << larger(Txz{1,2}, Txz{2,3}) << "\n";
}
https://repl.it/repls/LastPoliteType#main.cpp

Related

aggregate-initializable tuple like data structure

I want to store multiple non-movable types in a single variable.
At the very first, I have tried std::tuple at the very first, but it fails.
#include <tuple>
template<typename T>
struct No {
No(T){}
No(const No &) = delete;
No(No &&) = delete;
};
struct Handmade {
No<int> a;
No<double> b;
No<char> c;
};
template<typename T>
auto no() -> No<T> { return No<T>(T()); }
auto main() -> int
{
Handmade h = {no<int>(), no<double>(), no<char>()}; // good
auto tuple = std::make_tuple(no<int>(), no<double>(), no<char>()); // fails
return 0;
}
Here, Handmade type can be initialized through aggregate initialization.
However, std::tuple is not aggregate-initialzable, it doesn't work.
Since it should be variadic, I cannot write such type Handmade for my purpose.
Is it possible to implement such variadic tepmlate data structure in current C++ standard or is there any workaround?
Yes, you can write your own aggregate tuple like this:
template <int I, typename T>
struct MyTupleElem
{
T value{};
template <int J> requires(I == J) T &get() {return value;}
template <int J> requires(I == J) const T &get() const {return value;}
};
template <typename T, typename ...P>
struct MyTupleHelper;
template <int ...I, typename ...P>
struct MyTupleHelper<std::integer_sequence<int, I...>, P...>
: MyTupleElem<I, P>...
{
using MyTupleElem<I, P>::get...;
};
template <typename ...P>
struct MyTuple : MyTupleHelper<std::make_integer_sequence<int, sizeof...(P)>, P...> {};
template <typename ...P>
MyTuple(P &&...) -> MyTuple<std::decay_t<P>...>;
template <typename T>
struct No
{
T value;
No(T value) : value(value) {}
No(const No &) = delete;
No(No &&) = delete;
};
template <typename T>
No<T> no(T t) {return No<T>(t);}
int main()
{
MyTuple h = {no<int>(1), no<double>(2.3), no<char>('4')};
std::cout << h.get<0>().value << '\n';
std::cout << h.get<1>().value << '\n';
std::cout << h.get<2>().value << '\n';
}
And I think it's a good way to make tuples in general, even if you don't want aggregate-ness. Last time I tested, such tuples could tolerate more elements than the classic ones with the bases chained on top of each other.

How to arbitrarily enable or disable class method based on specific type?

I have a class like this:
struct X
{
enum Type { INT, FLOAT };
using val_t = std::tuple<int, float>;
X(Type t) : type(t) {}
Type type;
template<typename T>
X& operator =(T x)
{
// ???
static_assert(T is the same as `type');
// ???
std::get<type>(val) = x;
return *this;
}
val_t val;
};
Is it possible to assert at compile time if user tries to assign incompatible value?
For example:
X x1(X::INT);
x1 = 5; // OK
x1 = 3.14; // compilation error
Note: I prefer keeping the class as not a template because I need to keep its instances in collections (like std::vector etc).
You cannot: the value of type_ is run time data, compilation errors are not determined at runtime.
You could do:
enum Type { INT, FLOAT };
template<Type type_>
struct X {
using val_t = std::tuple<int, float>;
template<typename T>
X& operator =(T x) {
// ???
static_assert((type_==INT&&std::is_same<T,int>{})||(type_==FLOAT&&std::is_same<T,float>{}),
"types do not match"
);
std::get<T>(val) = x;
return *this;
}
val_t val;
};
X<INT> x1;
x1 = 5; // OK
x1 = 3.14; // compilation error
but I do not see much point.
One way would be to have a base type that does not do the checking just stores state, and a derived that knows its type.
struct Base{
enum {INT,FLOAT} Type;
// etc
};
template<Base::Type type>
struct Derived:private Base{
Derived():Base(type){}
using Base::some_method; // expose base methods
Base& get_base()&{return *this;}
Base get_base()&&{return std::move(*this);}
Base const& get_base()const&{return *this;}
template<class T>
Derived& operator=( T o){
static_assert((type_==INT&&std::is_same<T,int>{})||(type_==FLOAT&&std::is_same<T,float>{}),
"types do not match"
);
Base::operator=(std::move(o));
return *this;
}
};
Base does not check, at best it runtime asserts. Derived checks at compile time.
Niw when you know the type statically at compile time you use Derived<INT> d;; when you do not, or need to forget, use .get_base() or a Base b(type_enum_val);.
Considering that you have Type type; you can't assert at compiletime if type is INT or FLOAT or whatever you have. For that check you can only assert at runtime.
For everything else you can do a compiletime check, and a runtime check for using some template meta-programming:
namespace detail_tuple
{
template <typename T, std::size_t N, typename... ARGS>
struct get_by_type_impl {
enum {
kIdx = N
};
};
template <typename T, std::size_t N, typename... ARGS>
struct get_by_type_impl<T, N, T, ARGS...> {
enum {
kIdx = N
};
};
template <typename T, std::size_t N, typename U, typename... ARGS>
struct get_by_type_impl<T, N, U, ARGS...> {
enum {
kIdx = get_by_type_impl<T, N + 1, ARGS...>::kIdx
};
};
}
template <typename, typename>
struct validator;
template <typename T, typename... ARGS>
struct validator < T, std::tuple<ARGS...> >
{
static void validate(const std::size_t type_idx)
{
//compiletime checks
//get index of type T in ARGS...
constexpr auto ind = detail_tuple::get_by_type_impl<T, 0, ARGS...>::kIdx;
//check if index is valid
static_assert(ind < sizeof...(ARGS), "Type index out of bounds, type T is was not found in the tuple!");
//runtime checks
if (type_idx != ind)
std::cout << "Incompatible type index!\n";
}
};
struct X
{
enum Type
{
INT = 0,
FLOAT,
TYPE_COUNT,
};
using val_t = std::tuple<int, float>;
X(Type t) : type(t) {}
Type type;
template<typename T>
X& operator =(const T& x)
{
validator<T, val_t>::validate(type);
std::get<T>(val) = x;
return *this;
}
val_t val;
};
for that std::get uses type T instead of type

Passing temporary struct as template argument

I'm in the process of creating a vector class and am trying to figure out ways to reuse the maximum amount of code for different size vectors.
Here's a basic example:
template<typename T, unsigned int D>
class Vector
{
public:
union {
T v[D];
struct {
/* T x;
* T y;
* T z;
* T w;
*/
};
};
Vector()
{
for(unsigned int i=0; i<D; ++i)
(*this)[i] = T(0);
}
Vector(T scalar)
{
for(unsigned int i=0; i<D; ++i)
(*this)[i] = scalar;
}
inline T operator[](int i) { return (*this).v[i]; }
};
I want the member variables to be publicly accessible. Ex:
Vector<float,2> vec;
printf("X: %.2f, Y: %.2f\n", vec.x, vec.y);
What I'd like to do is something along the lines of this:
template<typename T>
class Vector2 : public Vector<T,2, struct { T x; T y; }> {};
template<typename T>
class Vector3 : public Vector<T,2, struct { T x; T y; T z; }> {};
and have it override a struct in the union:
template<typename T, unsigned int D, struct C>
class Vector
{
public:
union {
T v[D];
// Place the passed struct here
};
};
Is there any feasible way to do this? I do not want to use anything other than the standard library if possible. Thanks in advance.
EDIT: After reading upon all of the answers, I have understood that the way I am using unions is incorrect! Thank you to #M.M for pointing this out. I have since chosen to go a different route, but I have selected the answer that best fit what I was looking for at the time. Once again, thank you for all of the welcomed responses below!
What you are trying to do is not allowed.
Anyway, you can do this:
template<typename T>
struct S { T x; T y; };
template<typename T>
class Vector2 : public Vector<T,2,S<T>> {};
Or this:
template<typename T>
class Vector2 : public Vector<T,2,S> {};
In the second case, Vector can be defined as:
template<typename T, unsigned int D, template<typename> class S>
class Vector {
using MyStruct = S<T>;
// ...
union {
T v[D];
MyStruct myStruct;
};
};
It doesn't scale very well to a large D, but if you're just after the four to six variants I'm imagining, you could partial-specialize a base class:
#include <iostream>
template<typename T, size_t D>
struct VectorBase;
template<typename T>
struct VectorBase<T, 2>
{
constexpr VectorBase() : v{} {}
union {
T v[2];
struct { T x, y; };
};
};
template<typename T>
struct VectorBase<T, 3>
{
constexpr VectorBase() : v{} {}
union {
T v[3];
struct { T x, y, z; };
};
};
template<typename T>
struct VectorBase<T, 4>
{
constexpr VectorBase() : v{} {}
union {
T v[4];
struct { T x, y, z, w; };
};
};
template<typename T, size_t D>
struct Vector : public VectorBase<T, D>
{
using VectorBase<T, D>::v;
using size_type = decltype(D);
using value_type = T;
constexpr Vector() : VectorBase<T,D>{} {}
constexpr Vector(T scalar) {
std::fill(std::begin(v), std::end(v), scalar);
}
constexpr T& operator[](size_type i) const noexcept { return v[i]; }
constexpr const T& operator[](size_type i) noexcept { return v[i]; }
constexpr size_type size() const noexcept { return D; }
constexpr T* data() noexcept { return &v[0]; }
constexpr const T* data() const noexcept { return &v[0]; }
};
template<typename T>
using Vector2 = Vector<T, 2>;
template<typename T>
using Vector3 = Vector<T, 3>;
template<typename T>
using Vector4 = Vector<T, 4>;
int main() {
Vector3<int> v{1};
std::cout << v[0] << ", " << v.z << "\n";
return 0;
}
Live demo: http://ideone.com/T3QHoq
If I understood you correctly your main purpose was to to declare order of fields that corresponds to the array elements of templated class. You cannot do this directly as templates does not accept inline type as parameter. To workaround the problem you could play with non-type template parameters to bind some labels to given index of an array:
#include <cstdio>
#include <unordered_map>
#include <utility>
struct Label { } x, y, z, w;
template <Label&... labels>
struct Pack { };
template <class, class>
struct VectorParent;
template <Label&... labels, size_t... Is>
struct VectorParent<Pack<labels...>, std::index_sequence<Is...>> {
static std::unordered_map<Label *, size_t> label_map;
};
template <Label&... labels, size_t... Is>
std::unordered_map<Label *, size_t> VectorParent<Pack<labels...>, std::index_sequence<Is...>>::label_map = {{&labels, Is}...};
struct LabelNotFound { };
template <class T, size_t N, Label&... labels>
struct Vector:VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>> {
static_assert(N == sizeof...(labels),
"the cound of labels should corespond to the number of elements of the vector");
using VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>>::label_map;
T t[N];
T &operator->*(Label& l) {
auto it = label_map.find(&l);
if (it == label_map.end())
throw LabelNotFound{};
return t[it->second];
}
};
int main() {
Vector<float,2,x,y> vec;
vec->*x = 10.0f;
printf("X: %.2f, Y: %.2f\n", vec->*x, vec->*y); // prints: X: 10.00, Y: 0.00
//vec->*w = 10.1f; //would throw an exception LabelNotFound
}

Using SFINAE on non static data members?

I'm new to SFINAE and I'm trying to write a simple Vector template. What I'm trying to achieve is to enable the z member variable based on the dimensions set for the Vector.
I have tried to achieve this effect using the following code:
template<unsigned int DIMENSIONS>
class Vector {
// The x and y variables (same as z)
template<typename = typename std::enable_if<DIMENSIONS >= 3>::type>
/// <summary>
/// The z coordinate.
/// </summary>
Float& z;
Vector() : x(values[0]), y(values[1]) {
}
// Other member functions and variables
std::vector<float> values;
};
template <>
Vector<3>::Vector() : x(values[0]), y(values[1]), z(values[2]) {
}
This should enable the z variable when there are 3 or more dimensions. This makes the compiler complain with the following error:
'Vector<DIMENSIONS>::z': only static data member templates are allowed
Also, I'm not entirely sure how to use initialization lists with SFINAE in such a situation. Because if the dimensions are smaller than 3, z would not have to be initialized (since it wouldn't exist). So far I've used a specialized constructor for 3D vectors (see the code above).
But intelliisense still reports that Members 'x', 'y', 'z' are not initialized in this constructor.
Any help would be appreciated.
You could do something like this:
struct no_z_var {};
struct z_var
{
float z;
};
template<std::size_t n>
struct my_vector : std::conditional_t<( n >= 3 ), z_var, no_z_var>
{
float x, y;
};
int main()
{
my_vector<3> mv3;
mv3.z = 3.4f;
my_vector<2> mv2;
mv2.z = 3.4f; // error; no 'z'
}
However, is this a good solution/design? I'm not so sure; it can get messy. It will most likely present other difficulties during the implementation...
You simply can't conditionally enable variables like that. Your best bet is just to provide multiple specializations of Vector:
template <>
struct Vector<2> {
float x, y;
Vector(std::vector<float> const& values)
: x(values[0])
, y(values[1])
{ }
};
template <>
struct Vector<3> {
float x, y, z;
Vector(std::vector<float> const& values)
: x(values[0])
, y(values[1])
, z(values[2])
{ }
};
// etc.
Though it might be more straightforward to use an array instead:
template <size_t DIM>
struct Vector {
std::array<float, DIM> values;
Vector(std::vector<float> const& vs)
: Vector(vs, std::make_index_sequence<DIM>{})
{ }
private:
template <size_t... Is>
Vector(std::vector<float> const& vs, std::index_sequence<Is...> )
: values{{vs[Is]...}}
{ }
};
You could use inheritance.
template<int n>
struct VecBase;
template<>
struct VecBase<1> {
float x;
};
template<>
struct VecBase<2> : VecBase<1> {
float y;
};
template<>
struct VecBase<3> : VecBase<2> {
float z;
};
template<>
struct VecBase<4> : VecBase<3> {
float w;
};
And then define your vector class:
template<int n>
struct Vector : VecBase<n> {
// operations
};
If you want to make n-dimentional operation, you can use std::get and std::index_sequence. Let's start by making overloads for std::get:
namespace std {
template<size_t I, int n, enable_if_t<(I == 0 && I < n), int> = 0>
float& get(VecBase<n>& vec) {
return vec.x;
}
template<size_t I, int n, enable_if_t<(I == 1 && I < n), int> = 0>
float& get(VecBase<n>& vec) {
return vec.y;
}
template<size_t I, int n, enable_if_t<(I == 2 && I < n), int> = 0>
float& get(VecBase<n>& vec) {
return vec.z;
}
template<size_t I, int n, enable_if_t<(I == 3 && I < n), int> = 0>
float& get(VecBase<n>& vec) {
return vec.w;
}
}
Note that you will have to implement them for const.
Then, you can implement your operations by making a base class that implement operations:
template<int, typename>
struct VecOps;
template<int n, std::size_t... S>
struct VecOps<n, std::index_sequence<S...>> : VecBase<n> {
float dotp(Vector<n>& vec) const {
// Where sum is adding each parameter variadically.
return sum((std::get<S>(*this) * std::get<S>(vec))...);
}
};
And finally, make Vector extending VecOps:
template<int n>
struct Vector : VecOps<n, std::make_index_sequence<n>> {};
Note that I don't have a compiler at my disposition for the moment. If your got compiler error, just leave a comment and I'll check this out.
Specialize the entrie class for 1, 2, 3 dimensions if you want this, i.e., template<> class Vector<3> { ... }.
You don't really need SFINAE here. Just use specialization:
template<unsigned int DIMENSIONS>
class Vector {
template<int I>
struct ZContainer {};
template<> struct ZContainer<3> {
float z;
};
ZContainer<DIMENSIONS> possibleZ;
};
This has the advantage that you don't need additional templates. You can just add functions to the ZContainers for your class behavior.

How to work around partial specialization of function template?

For example, I have a class:
class A
{
enum {N = 5};
double mVariable;
template<class T, int i>
void f(T& t)
{
g(mVariable); // call some function using mVariable.
f<T, i+1>(t); // go to next loop
}
template<class T>
void f<T, N>(T& t)
{} // stop loop when hit N.
};
Partial specialization is not allowed in function template. How do I work around it in my case?
I slightly changed the example of Arne Mertz, like:
template<int n>
struct A
{
enum {N = n};
...
};
and use A like:
A<5> a;
The I cannot compile on Visual Studio 2012. Is it a compiler bug or something else? It is quite strange.
EDIT: Checked. It is a Visual Studio bug. :(
I think Nim gives the most simple way to implement it.
The most straight forward solution is to use a template class instead of a function:
class A
{
enum {N = 5};
double mVariable;
template <class T, int i>
struct fImpl {
static_assert(i<N, "i must be equal to or less than N!");
static void call(T& t, A& a) {
g(a.mVariable);
fImpl<T, i+1>::call(t, a);
}
};
template<class T>
struct fImpl<T,N> {
static void call(T&, A&) {} // stop loop when hit N.
};
public:
template<class T, int i>
void f(T& t)
{
fImpl<T, i>::call(t,*this);
}
};
Example link
You can define a helper class:
template <int i, int M>
struct inc_up_to
{
static const int value = i + 1;
};
template <int i>
struct inc_up_to<i, i>
{
static const int value = i;
};
template<class T, int i>
void f(T& t)
{
if (i < N) {
g(mVariable); // call some function using mVariable.
f<T, inc_up_to<i, N>::value>(t);
}
}
It stops the compile-time recursion by making f<T, N> refer to f<T, N>, but that call is avoided by the run-time condition, breaking the loop.
A simplified and more robust version of the helper (thanks #ArneMertz) is also possible:
template <int i, int M>
struct inc_up_to
{
static const int value = (i >= M ? M : i + 1); // this caps at M
// or this:
static const int value = (i >= M ? i : i + 1); // this leaves i >= M unaffected
};
This doesn't even need the partial specialisation.
With c++11 support, you can do the following:
#include <iostream>
#include <type_traits>
using namespace std;
struct A
{
enum {N = 5};
double mVariable;
void g(int i, double v)
{ std::cout << i << " " << v << std::endl; }
template<int i, class T>
typename enable_if<i >= N>::type f(T& t)
{} // stop loop when hit N.
template<int i, class T>
typename enable_if<i < N>::type f(T& t)
{
g(i, mVariable); // call some function using mVariable.
f<i+1, T>(t); // go to next loop
}
};
int main(void)
{
A a;
int v = 0;
a.f<0>(v);
}
Main reason I like is that you don't need any of the cruft as required by the previous answers...
You can emulate partial specialization of function template with function overloading:
#include <type_traits>
class A
{
enum {N = 5};
double mVariable;
// ...
void g(double)
{
// ...
}
public:
template<class T, int i = 0>
void f(T& t, std::integral_constant<int, i> = std::integral_constant<int, i>())
{
g(mVariable);
f(t, std::integral_constant<int, i + 1>());
}
template<class T>
void f(T& t, std::integral_constant<int, N>)
{
}
};
Example of using:
A a;
int t = 0;
a.f(t);
a.f(t, std::integral_constant<int, 2>()); // if you want to start loop from 2, not from 0
It is a C++11 solution, however (not so much because of std::integral_constant class, but because of default template parameter of function template). It can be made shorter using some additional C++11 features:
template<int i>
using integer = std::integral_constant<int, i>;
template<class T, int i = 0>
void f(T& t, integer<i> = {})
{
g(mVariable);
f(t, integer<i + 1>());
}
template<class T>
void f(T& t, integer<N>)
{
}