I'm trying to implement lexicographic comparison for std::tuple. I know the standard provides this. I'm doing it as a TMP exercise. I can't see why the code below doesn't work. Can anyone point me in the right direction?
I know the code below assumes operands of the same type. I am happy making this as a simplifying assumption.
I've looked at the VC++ 2013 and GCC 4.7 implementations. They both use non-standard helper classes to get the tail (i.e. all but the left-most element) from a tuple. I'd like to solve the problem with as little scaffolding as possible. Is it possible to do tuple comparison without something like get_tail?
#include <iostream>
#include <string>
#include <tuple>
// Pseudo-recursion.
template<class tupleT,std::size_t N>
struct tuple_ops {
static bool less(const tupleT& x,const tupleT& y) {
return std::get<N-1>(x) < std::get<N-1>(y) ||
( !(std::get<N-1>(y) < std::get<N-1>(x)) &&
tuple_ops<tupleT,N-1>::less(x,y) );
}
};
// Base Case.
template<class tupleT>
struct tuple_ops<tupleT,1> {
static bool less(const tupleT& x,const tupleT& y) {
return std::get<0>(x) < std::get<0>(y);
}
};
// Convenience wrapper.
template<class... T>
bool operator<(const std::tuple<T...>& x,const std::tuple<T...>& y) {
return tuple_ops<decltype(x),sizeof...(T)>::less(x,y);
}
int main() {
using namespace std;
auto tup0 = make_tuple(3.14,string("foo"),2.71);
auto tup1 = make_tuple(4.01,string("foo"),2.01);
auto tup2 = make_tuple(1,string("bar"),5);
auto tup3 = make_tuple(1,string("foo"),5);
cout << (::operator<(tup0,tup1)) << ' '
<< (::operator<(tup2,tup3)) << ' '
<< !(::operator<(tup1,tup0)) << ' '
<< !(::operator<(tup3,tup2)) << ' ';
return 0;
}
Output: 0 1 0 1
Correct output would be: 1 1 1 1
Thanks in advance.
The reason your code doesn't work is that your comparisons are backwards. Your first call is:
return tuple_ops<decltype(x),sizeof...(T)>::less(x,y);
which will call tuple_ops<Type, 3>::less(), the first operation of which compares std::get<2>(x) and std::get<2>(y). So you're comparing the last elements first.
You have to start at 0 and go up to N, so you'd have to rewrite your first-level call to be:
return tuple_ops<decltype(x),0,sizeof...(T)>::less(x,y);
with the terminating case now being:
template <typename Tuple, size_t N>
struct tuple_ops<Tuple, N, N> {
static bool less(const Tuple&, const Tuple&) { return false; }
};
A simpler way to avoid specializations would be to use an index sequence (and borrowing from Yakk's now-deleted answer to add more functionality):
template <class X, class Y>
bool operator<(const X& x, const Y& y) {
return is_less(x, y,
std::make_index_sequence<std::min(std::tuple_size<X>{},
std::tuple_size<Y>{})>{});
}
Have an overload for the empty case:
template <typename X, typename Y>
bool is_less(X const&, Y const&, std::index_sequence<> ) {
return std::tuple_size<X>{} < std::tuple_size<Y>{};
}
and an overload for the recursive case:
template <typename X, typenmae Y, size_t I, size_t... Is>
bool is_less(X const& x, Y const& y, std::index_sequence<I, Is...> ) {
if (std::get<I>(x) < std::get<I>(y)) {
return true;
}
else if (std::get<I>(y) < std::get<I>(x)) {
return false;
}
else {
return is_less(x, y, std::index_sequence<Is...>{});
}
}
Working like a charm. Here's a version of the test program, incorporating Barry's tips.
#include <iostream>
#include <string>
#include <tuple>
// Pseudo-recursion.
template<class tupleT,std::size_t J,std::size_t N>
struct tuple_ops {
static bool less(const tupleT& x,const tupleT& y) {
return std::get<J>(x) < std::get<J>(y) ||
( !(std::get<J>(y) < std::get<J>(x)) &&
tuple_ops<tupleT,J+1,N>::less(x,y) );
}
};
// Base Case.
template <typename Tuple, size_t N>
struct tuple_ops<Tuple,N,N> {
static bool less(const Tuple&, const Tuple&) {return false;}
};
// Convenience wrapper.
template<class... T>
bool operator<(const std::tuple<T...>& x,const std::tuple<T...>& y) {
return tuple_ops<decltype(x),0,sizeof...(T)>::less(x,y);
}
int main() {
using namespace std;
auto tup0 = make_tuple(3.14,string("foo"),2.71);
auto tup1 = make_tuple(4.01,string("foo"),2.01);
auto tup2 = make_tuple(1,string("bar"),5);
auto tup3 = make_tuple(1,string("foo"),5);
cout << (::operator<(tup0,tup1)) << ' '
<< (::operator<(tup2,tup3)) << ' '
<< !(::operator<(tup1,tup0)) << ' '
<< !(::operator<(tup3,tup2)) << ' ';
return 0;
}
Thanks again.
Related
I want to make a generic print(x) function, which behaves different for different types.
What I have so far works for all container types, including the one I wrote myself. However, either the "wrong" function is getting called or it won't compile due to ambiguity.
Here is my code:
#include <iostream>
#include <concepts>
class Container
{
int x, y, z;
public:
Container(int a, int b, int c) : x(a), y(b), z(c) {}
Container() : x(0), y(0), z(0) {}
std::size_t size() const { return 3; }
const int& operator[] (std::size_t index) const { if(index == 0) return x; else if(index == 1) return y; else return z; }
int& operator[] (std::size_t index) { if(index == 0) return x; else if(index == 1) return y; else return z; }
};
template<typename T>
concept printable_num = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::same_as<int&>;
};
template<printable_num T>
void print(const T& t) {
std::size_t i = 0;
for(;i < t.size() - 1; i++)
std::cout << t[i] << ", ";
std::cout << t[i] << std::endl;
}
template<typename T>
concept printable = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::convertible_to<char>;
};
template<printable T>
void print(const T& t) {
std::size_t i = 0;
for(;i < t.size() - 1; i++)
std::cout << t[i];
std::cout << t[i] << std::endl;
}
int main()
{
Container c{1, 2, 3};
print(c);
Container empty;
print(empty);
std::string s{"this is some string"};
print(s);
return 0;
}
As you can see, I want to print a separator if the type returned from operator[] is int&. This does not compile due to ambiguity.
Is there a way to make this compile and to get me where I want (call the print function without the separator for std::string and the one with separator for my own Container type)?
Given an integer (or lvalue to one), would you not agree that it is convertible to a char? The constraints check exactly what you have them check for the types in your question.
One way to tackle it would be by constraint subsumption. Meaning (in a very hand wavy fashion) that if your concepts are written as a conjugation (or disjunction) of the same basic constraints, a compiler can normalize the expression to choose the "more specialized one". Applying it to your example..
template<typename T>
concept printable = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::convertible_to<char>;
};
template<typename T>
concept printable_num = printable<T> && requires (T t, std::size_t s)
{
{ t[s] } -> std::same_as<int&>;
};
Note how we used printable to define printable_num as the "more specific" concept. Running this example, we get the output you are after.
I'm studying c++ templates and reading <<C++ Templates: The Complete Guide>>. I don't understand the flowing about expression template:
The code as following:
//exprarray.h
#include <stddef.h>
#include <cassert>
#include "sarray.h"
template<typename T>
class A_Scale
{
public:
A_Scale(T const& t):value(t){}
T operator[](size_t) const
{
return value;
}
size_t size() const
{
return 0;
}
private:
T const& value;
};
template<typename T>
class A_Traits
{
public:
typedef T const& exprRef;
};
template<typename T>
class A_Traits<A_Scale<T> >
{
public:
typedef A_Scale<T> exprRef;
};
template<typename T,typename L1,typename R2>
class A_Add
{
private:
typename A_Traits<L1>::exprRef op1;
typename A_Traits<R2>::exprRef op2;
public:
A_Add(L1 const& a,R2 const& b):op1(a),op2(b)
{
}
T operator[](size_t indx) const
{
return op1[indx] + op2[indx];
}
size_t size() const
{
assert(op1.size()==0 || op2.size()==0 || op1.size() == op2.size());
return op1.size() != 0 ? op1.size() : op2.size();
}
};
template<typename T,typename L1,typename R2>
class A_Mul
{
private:
typename A_Traits<L1>::exprRef op1;
typename A_Traits<R2>::exprRef op2;
public:
A_Mul(L1 const& a,R2 const& b):op1(a),op2(b)
{
}
T operator[](size_t indx) const
{
return op1[indx] * op2[indx];
}
size_t size() const
{
assert(op1.size()==0 || op2.size()==0 || op1.size() == op2.size());
return op1.size() != 0 ? op1.size():op2.size();
}
};
template<typename T,typename Rep = SArray<T> >
class Array
{
public:
explicit Array(size_t N):expr_Rep(N){}
Array(Rep const& rep):expr_Rep(rep){}
Array& operator=(Array<T> const& orig)
{
assert(size() == orig.size());
for (size_t indx=0;indx < orig.size();indx++)
{
expr_Rep[indx] = orig[indx];
}
return *this;
}
template<typename T2,typename Rep2>
Array& operator=(Array<T2,Rep2> const& orig)
{
assert(size() == orig.size());
for (size_t indx=0;indx<orig.size();indx++)
{
expr_Rep[indx] = orig[indx];
}
return *this;
}
size_t size() const
{
return expr_Rep.size();
}
T operator[](size_t indx) const
{
assert(indx < size());
return expr_Rep[indx];
}
T& operator[](size_t indx)
{
assert(indx < size());
return expr_Rep[indx];
}
Rep const& rep() const
{
return expr_Rep;
}
Rep& rep()
{
return expr_Rep;
}
private:
Rep expr_Rep;
};
template<typename T,typename L1,typename R2>
Array<T,A_Add<T,L1,R2> >
operator+(Array<T,L1> const& a,Array<T,R2> const& b)
{
return Array<T,A_Add<T,L1,R2> >(A_Add<T,L1,R2>(a.rep(),b.rep()));
}
template<typename T,typename L1,typename R2>
Array<T,A_Mul<T,L1,R2> >
operator*(Array<T,L1> const& a,Array<T,R2> const& b)
{
return Array<T,A_Mul<T,L1,R2> >(A_Mul<T,L1,R2>(a.rep(),b.rep()));
}
template<typename T,typename R2>
Array<T,A_Mul<T,A_Scale<T>,R2> >
operator*(T const& a,Array<T,R2> const& b)
{
return Array<T,A_Mul<T,A_Scale<T>,R2> >(A_Mul<T,A_Scale<T>,R2>(A_Scale<T>(a),b.rep()));
}
The test code:
//test.cpp
#include "exprarray.h"
#include <iostream>
using namespace std;
template <typename T>
void print (T const& c)
{
for (int i=0; i<8; ++i) {
std::cout << c[i] << ' ';
}
std::cout << "..." << std::endl;
}
int main()
{
Array<double> x(1000), y(1000);
for (int i=0; i<1000; ++i) {
x[i] = i;
y[i] = x[i]+x[i];
}
std::cout << "x: ";
print(x);
std::cout << "y: ";
print(y);
x = 1.2 * x;
std::cout << "x = 1.2 * x: ";
print(x);
x = 1.2*x + x*y;
std::cout << "1.2*x + x*y: ";
print(x);
x = y;
std::cout << "after x = y: ";
print(x);
return 0;
}
My questions is why A_Traits for A_Scale is by value not by reference.
template<typename T>
class A_Traits
{
public:
typedef T const& exprRef;
};
template<typename T>
class A_Traits<A_Scale<T> >
{
public:
typedef A_Scale<T> exprRef;
};
The reason from the book as following:
This is necessary because of the following: In general, we can declare them to be references because most temporary nodes are bound in the top-level expression and therefore live until the end of the evaluation of that complete expression. The one exception are the A_Scalar nodes. They are bound within the operator functions and might not live until the end of the evaluation of the complete expression. Thus, to avoid that the members refer to scalars that don't exist anymore, for scalars the operands have to get copied "by value."
More detail please refer to the chapter 18 of C++ Templates: The Complete Guide
Consider, for example, the right hand side of
x = 1.2*x + x*y;
What the quote says is that this is composed of two different categories.
The heavy array x and y objects are not defined within this expression, but rather before it:
Array<double> x(1000), y(1000);
So, as you build expressions using them, you don't have to worry whether they're still alive - they were defined beforehand. Since they're heavy, you want to capture them by reference, and, fortunately, their lifetime makes that possible.
Conversely, the lightweight A_Scale objects are generated within the expression (e.g., implicitly by the 1.2 above). Since they're temporaries, you have to worry about their lifetime. Since they're lightweight, it's not a problem.
That's the rationale for the traits class differentiating between them: the former are by reference, and the latter are by value (they are copied).
I'm writing C++ and missing the clarity of Python. But I know that C++ has been evolving and wondering if there's a nicer way to do something like this:
if (foo != bar && foo != baz)
In Python I would do this:
if foo not in {bar, baz}:
Is there a fancy feature in C++11 or C++14 that allows me to do something similarly readable?
Edit: A lot of people are wondering why I'm trying to replace something so short. I'm not, but I didn't want to make my example as ugly and unreadable as the original code. It's more like:
if (somelongvariablename.somelongmethodname() !=
SomeReallyLongNamespace::AndAnotherSubClassname::A_LONG_CONSTANT_NAME &&
somelongvariablename.somelongmethodname() !=
SomeReallyLongNamespace::AndAnotherSubClassname::ANOTHER_LONG_CONSTANT_NAME) {
// foo
How about something like this:
#include <type_traits>
#include <tuple>
#include <utility>
template <typename ...Args> struct InT: std::tuple<Args...>
{
template <typename ...Brgs>
explicit InT(Brgs &&... brgs)
: std::tuple<Args...>(std::forward<Brgs>(brgs)...) {}
template <typename T, std::size_t ...I>
bool noteq(T && t, std::index_sequence<I...>) const
{
return (true && ... && (t != std::get<I>(*this)));
}
};
template <typename ...Args>
InT<Args &&...> AnyOf(Args &&... args)
{
return InT<Args &&...>(std::forward<Args>(args)...);
}
template <typename T, typename ...Args>
bool operator!=(T && t, InT<Args...> in)
{
return in.noteq(std::forward<T>(t), std::index_sequence_for<Args...>());
}
Usage:
if (x != AnyOf(1, 3, 5)) { f(); }
We can get this syntax:
int main() {
if (foo *in* std::tie(bar, baz)) {
}
}
live example.
It also works with C arrays or std containers or the like on the right hand side of *in*.
This should be zero overhead after the optimizer gets its teeth into it.
Negating is just:
if (!(foo *in* std::tie(bar, baz)))
as I don't think a special case is a good plan. If you want the foo *not in* std::tie(bar, baz)) syntax, see bottom of this post.
First, a named operator library:
namespace named_operator {
template<class D>struct make_operator{constexpr make_operator(){}};
template<class T, char, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, '*', Op> operator*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, '*', Op>&& lhs, Rhs&& rhs )
-> decltype( invoke( std::declval<Lhs>(), Op{}, std::declval<Rhs>() ) )
{
return invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
which is about 12 lines long, and makes named operators easy.
Now we make a named operator.
namespace my_ns {
constexpr struct in_tag:named_operator::make_operator {} in {};
}
using my_ns::in;
It needs an action. The C++17 version is easy:
namespace my_ns {
// foo in tuple support:
template<class T, class...Args>
bool invoke( T const& lhs, in_tag, std::tuple<Args...> const& rhs ) {
return std::apply( [&](auto&&...args){
return (false || ... || (lhs == args));
}, rhs);
}
// foo in container support:
template<class T, class Container>
bool invoke( T const& lhs, in_tag, Container const& rhs ) {
using std::begin; using std::end;
auto it = std::find( begin(rhs), end(rhs), lhs );
return it != end(rhs);
}
}
The C++11 tuple support version is a bit trickier, because of the lack of std::apply and fold expansion:
namespace my_ns {
// tuple support:
template<class T, class...Args, std::size_t...Is>
bool invoke( T const& lhs, in_tag, std::tuple<Args...> const& rhs, std::index_sequence<Is...> ) {
bool retval = false;
using discard=int[];
(void)discard{ 0,(void(
retval = retval || (lhs == std::get<Is>(rhs))
),0)... };
return retval;
}
template<class T, class...Args>
bool invoke( T const& lhs, in_tag, std::tuple<Args...> const& rhs ) {
return invoke(lhs, in_tag{}, rhs, std::index_sequence_for<Args...>{} );
}
// container support is identical to C++17 version
}
As mentioned above, if you want
if (foo *not in* std::tie(bar, baz))
I can do it.
Add a not_in operator:
namespace my_ns {
constexpr struct not_in_tag:named_operator::make_operator<not_in_tag> {} not_in {};
}
using my_ns::not_in;
We then define ! that toggles between them:
namespace my_ns {
constexpr not_in_tag operator!(in_tag){return {};}
constexpr in_tag operator!(not_in_tag){return {};}
|
and what the not_in operator does:
namespace my_ns {
template<class T, class Rhs>
bool invoke( T const& lhs, not_in_tag, Rhs const& rhs ) {
return !invoke(lhs, in_tag{}, rhs );
}
}
for invoke.
Now we get
if (foo *not in* std::tie(bar, baz)) {
std::cout << "foo not in {bar,baz}\n";
}
if (foo *not in* std::make_tuple(bar, baz, 3)) {
std::cout << "foo not in {bar,baz, 3}\n";
}
or
if (foo *not_in* std::tie(bar, baz)) {
std::cout << "foo not in {bar,baz}\n";
}
or
if (foo *!in* std::tie(bar, baz)) {
std::cout << "foo not in {bar,baz}\n";
}
whichever you want.
live example
I strongly advise you not to pollute code with fancy stuff unless needed.
The following C++14 solution offers an infix syntax as in Python, in case you have more than two values to compare to:
#include <tuple>
#include <utility>
template <typename... T>
struct in_checker : std::tuple<T...> {
using std::tuple<T...>::tuple;
template <typename U, std::size_t... Is>
constexpr bool contains(U const& u, std::index_sequence<Is...>) const {
for (auto b : {std::get<Is>(*this) == u...})
if (b) return true;
return false;
}
template <typename U>
constexpr bool contains(U const& u) const {
return contains(u, std::index_sequence_for<T...>{});}
};
template <typename U, typename... T>
constexpr bool operator==(U const& u, in_checker<T...> const& in) {
return in.contains(u);}
template <typename U, typename... T>
constexpr bool operator!=(U const& u, in_checker<T...> const& in) {
return !(u == in);}
template <typename... T>
constexpr in_checker<T...> in(T const&... t) {return std::tie(t...);}
#include <iostream>
int main() {
int t = 2;
if (t == in(1, 2, 3))
std::cout << "Congrats";
if (t != in(1, 3, 4))
std::cout << "... again!";
}
Demo.
Not really elegant, I suppose, but you can write a simple isIn() template function
template <typename T>
bool isIn (const T & val, const std::set<T> & s)
{ return s.cend() != s.find(val); }
and the following is a simple case of use when T is int
#include <set>
#include <iostream>
template <typename T>
bool isIn (const T & val, const std::set<T> & s)
{ return s.cend() != s.find(val); }
int main ()
{
int bar = 5;
int baz = 3;
int foo = 0;
if ( false == isIn(foo, {bar, baz}) )
std::cout << foo << " isn\'t in set" << std::endl;
else
std::cout << foo << " is in set" << std::endl;
foo = 3;
if ( false == isIn(foo, {bar, baz}) )
std::cout << foo << " isn\'t in set" << std::endl;
else
std::cout << foo << " is in set" << std::endl;
return 0;
}
--- post edit edit --
#guidoism: I think your question is interesting in a more general way but, if you must only check somelongmethodname() against values of an enum, I think a readable solution could be the good old switch
using SomeReallyLongNamespace::AndAnotherSubClassname;
switch ( somelongvariablename.somelongmethodname() )
{
case A_LONG_CONSTANT_NAME:
case ANOTHER_LONG_CONSTANT_NAME:
// do nothing (or something, if you like)
break;
default:
// do something
break;
}
#include <iostream>
#include <initializer_list>
using namespace std;
template<typename T>
initializer_list<T> in(initializer_list<T> K)
{
return K;
}
template<typename T>
bool operator !=(T A, initializer_list<T> B)
{
bool R = true;
for (auto E : B)R = R && (A != E);
return R;
}
int main()
{
if (1 != in({2,3,4}))
{
cout << "Wow" << endl;
}
return 0;
}
in this way we can make the code more readable like
1 != in({2,3,4})
EDIT:
Found a more readable way.
#include <iostream>
#include <initializer_list>
using namespace std;
template<typename T>
initializer_list<T> o(initializer_list<T> K)
{
return K;
}
class not_i
{
};
class not_i_helper1
{
public:
int S;
};
not_i_helper1 operator<(int A, not_i P)
{
not_i_helper1 K;
K.S = A;
return K;
}
bool operator>(not_i_helper1 S, initializer_list<int> B)
{
bool R = true;
for (auto E : B)R = R && (S.S != E);
return R;
}
not_i not_in;
int main()
{
if (1 < not_in > o({ 2,3,4 }))
{
cout << "Success!" << endl;
}
else
{
cout << "Huh?" << endl;
}
return 0;
}
now we can use 1 < not_in > o({ 2,3,4 })
I do like the elegant simplicity of the Python syntax:
if foo not in {bar, baz}
In a scripting language minimalistic code is the highest good. But under the hood that line is going to:
Construct a simple container something like C++'s initializer_list
Insert references to bar and baz into the container
Get a reference to the 1st item in the container
Compare that reference to foo if equal destroy the container and jump to the false branch
Get the next reference in the container
Compare that reference to foo if equal destroy the container and jump to the false branch
Destroy the container and fall into the true branch
In C++ the highest good is speed so let's look at the way that we're forced to do it in C++:
if(foo != bar && foo != baz)
Compare foo to bar if equal jump to the false branch
Compare foo to baz if equal jump to the false branch
Fall through to the true branch
This is not to say that a good compiler couldn't optimize away the container in the Python if-statement, but if these variables represent objects with differing construction rules that may be all but impossible. If C++ does grace us with this syntax, I'll be the second to adopt it, right after you. But for now the construction of a temporary container to veil individual comparisons is a poor decision for 2 reasons:
1. The unintended cost of container construction may not be optimized away
2. Since there are not standard provided keywords the cost to the reader to figure out what's happening will outweigh the elegance gained by using a container
So for now the best solution is still old reliable: if(foo != bar && foo != baz)
That's not say we can't use a container in C++ though, given the type of foo, bar, and baz is int you could do either of these great evils:
if(basic_string<int>{bar, baz}.find(foo) == -1)
if(set<int>{bar, baz}.insert(foo).second)
if(!set<int>{bar, baz}.count(foo))
EDIT:
After seeing your edit to your question it should be said that even if you could use the Python syntax that only saves you: characters-in-foo + 4 characters Given the code:
if (somelongvariablename.somelongmethodname() != SomeReallyLongNamespace::AndAnotherSubClassname::A_LONG_CONSTANT_NAME &&
somelongvariablename.somelongmethodname() != SomeReallyLongNamespace::AndAnotherSubClassname::ANOTHER_LONG_CONSTANT_NAME)
If what your saying is that you have public, static variables like this:
namespace SomeReallyLongNamespace {
struct AndAnotherSubClassname{
static const auto A_LONG_CONSTANT_NAME = 13;
static const auto ANOTHER_LONG_CONSTANT_NAME = 42;
};
}
Then a using-statement will eliminate a ton of typing, not just here but everywhere within the scope that the using is defined:
using namespace SomeReallyLongNamespace;
if (somelongvariablename.somelongmethodname() != AndAnotherSubClassname::A_LONG_CONSTANT_NAME &&
somelongvariablename.somelongmethodname() != AndAnotherSubClassname::ANOTHER_LONG_CONSTANT_NAME)
Next presuming that somelongvariablename.somelongmethodname() is a const method the best practice is to mirror it's return in a constant temporary, thereby only requiring you call the method once, again improving our code:
using SomeReallyLongNamespace::AndAnotherSubClassname;
const auto& foo = somelongvariablename.somelongmethodname();
if(foo != AndAnotherSubClassname::A_LONG_CONSTANT_NAME && foo != AndAnotherSubClassname::ANOTHER_LONG_CONSTANT_NAME)
There obviously are a couple conditions there, but I'd say that if you can pull this off your concern has greatly improved your code to the point that you'd only save 7 characters with the Python syntax, returning the old faithful C++ syntax to a viable contender.
If your case is really simple you can just do this:
for (auto& e : {bar, baz})
if (foo == e)
{ /* found */ };
note, as is, this doesn't have a way to say if isn't in there.
This one is a one-liner on my 15" 16:9 laptop :D
#include <iostream>
#include <set>
int main() {
for(std::set<int> omg({1, 2, 3, 4}); omg.find(42) == omg.cend(); ) { std::cout << "There's no Answer." << std::endl; break; }
}
I am new to SFINAE. I have a template that I would like to be able to accept classes that the size could be determined simply calling sizeof(x) or in case the value is dynamic it will require x.size().
I am trying to wrap my head around how as smooth as possible this could looks like and I think interface: size_t size(const Item& item) seems to be good enough.
The following is an example that works:
#include <iostream>
#include <cstdio>
#include <type_traits>
template <typename T>
class Fixed {
public:
typedef T Item;
static const bool kFixedSize = true;
static size_t size() {
return sizeof(T);
}
};
template <typename T>
class Dynamic {
public:
typedef T Item;
static const bool kFixedSize = false;
static size_t size(const T& item) {
return item.size();
}
};
template <typename T>
class Serialize {
public:
template <typename = typename std::enable_if<T::kFixedSize> >
size_t size(typename T::Item&) {
return T::size();
}
template <typename = typename std::enable_if<!T::kFixedSize> >
size_t size(const typename T::Item& item) {
return T::size(item);
}
};
int main() {
Serialize< Fixed<int> > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
Serialize< Dynamic<std::string> > dynamic;
std::cout << dynamic.size("string") << std::endl;
return 0;
}
It has an issues though one is: size_t size(typename T::Item&) and the other is size_t size(const typename T::Item& item) else the compiler compliance that I am overloading the template. The second is it seems like too match very tricky code to achieve the goal - is there better ways to do this?
I believe you want something like this
//class hierarchy to set the priority for type matching
struct second_priority
{
};
struct first_priority : public second_priority
{};
template<typename T>
auto size_impl(T const & data, second_priority t) -> int
{
return sizeof(data);
}
template<typename T>
auto size_impl(T const & data , first_priority t) -> decltype(data.size(),int())
{
return data.size();
}
template<typename T>
int size(T const & data )
{
return size_impl(data,first_priority{});
}
I think #Gautam Jha presented a nice solution using SFINAE. You can shorten it a bit by using ellipsis for the 'else' case, so you don't need to use this auxiliary class and it's inheritance:
template<typename T>
auto size_impl(T const & item, int) -> decltype(item.size())
{
return item.size();
}
template<typename T>
auto size_impl(T const & item, ...) -> size_t
{
return sizeof(T);
}
template<typename T>
auto size(T const & item) -> size_t
{
return size_impl(item, 0);
}
It's cool that you're playing around with SFINAE, but usually there are simpler (i.e. to read and to understand) ways to achieve the same, see the solution of POW (which has unfortunately been deleted).
Since all you want to do is call different functions to get the size in Dynamic or Fixed, you can just implement these classes differently and use them in Serialize:
#include <iostream>
#include <cstdio>
#include <type_traits>
template <typename T>
class Fixed {
public:
typedef T Item;
static size_t size(const T&) {
return sizeof(T);
}
};
template <typename T>
class Dynamic {
public:
typedef T Item;
static size_t size(const T& item) {
return item.size();
}
};
template <typename T>
class Serialize {
public:
size_t size(typename T::Item const& x) {
return T::size(x);
}
};
int main() {
Serialize< Fixed<int> > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
Serialize< Dynamic<std::string> > dynamic;
std::cout << dynamic.size( std::string{"string"} ) << std::endl;
return 0;
}
However, I would consider using a type-trait or a free function to do the same. This would be more extensible, because you have to just provide a new trait or an overload for new types, e.g. some container which has only a length method.
#include <iostream>
#include <cstdio>
#include <type_traits>
size_t size(int) {return sizeof(int);}
size_t size(std::string const& s) {return s.size();}
template<typename T>
struct size_trait
{
};
template<>
struct size_trait<int>
{
static size_t size(int) {return sizeof(int);}
};
template<>
struct size_trait<std::string>
{
static size_t size(std::string const& x) {return x.size();}
};
template <typename T>
class Serialize {
public:
size_t size(T const& x) {
return ::size(x);
}
size_t size_(T const& x) {
return size_trait<T>::size(x);
}
};
int main() {
Serialize< int > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
std::cout << fixed.size_(a) << std::endl;
Serialize< std::string > dynamic;
std::cout << dynamic.size( std::string{"string"} ) << std::endl;
std::cout << dynamic.size_( std::string{"string"} ) << std::endl;
return 0;
}
I would like to define a simple template function which takes a runtime value and determines if it is a member of some set of possible values.
Usage:
int x; // <- pretend this came from elsewhere...
if (isoneof(x, {5,3,9,25}) ...
Something like:
template <typename T, size_t size>
bool isoneof(T value, T (&arr)[size])
{
for (size_t i = 0; i < size; ++i)
if (value == arr[i])
return true;
return false;
}
I assume that this is doomed to failure, as I don't see how one can create a static array inline.
I can use:
int kPossibilities[] = {5,3,9,25};
if (isoneodf(6, kPossibilities)) ...
With a minor change to isoneof:
template <typename T1, typename T2, size_t size>
bool isoneof(T1 value, const T2 (&arr)[size])
{
for (size_t i = 0; i < size; ++i)
if (value == arr[i])
return true;
return false;
}
Which also makes it a tad more flexible.
Does anyone have an improvement to offer? A better way to define a "set of static values inline"?
If you like such things, then you will be a very happy user of Boost.Assign.
Boost.Assign actually proves that such semantics are possible, however one look at the source of assign will convince you that you don't want to do that by yourself :)
You will be able to create something like this however:
if (isoneof(x, list_of(2)(3)(5)(7)(11)) { ...
... the downside being you'd have to use boost::array as the parameter instead of a built-in array (thanks, Manuel) -- however, that's a nice moment to actually start using them :>
It's possible in the next C++ standard.
Up till then, you can work around it by e.g. overloading operator, for a static object that starts a static array.
Note: this implementation is O(n^2) and may be optimized - it's just to get the idea.
using namespace std;
template< typename T, size_t N >
struct CHead {
T values[N];
template< typename T > CHead<T,N+1> operator,( T t ) {
CHead<T,N+1> newhead;
copy( values, values+N, newhead.values);
newhead.values[N]=t;
return newhead;
}
bool contains( T t ) const {
return find( values, values+N, t ) != values+N;
}
};
struct CHeadProto {
template< typename T >
CHead<T,1> operator,( T t ) {
CHead<T,1> h = {t};
return h;
}
} head;
int main()
{
assert( (head, 1,2,3,4).contains(1) );
return 0;
}
For the sake of completeness, I'll post a solution that uses Boost.MPL. The following works, but I think Kornel's solution is best.
#include <iostream>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector_c.hpp>
struct Contains
{
Contains(int value, bool& result) : value(value), result(result)
{
result = false;
}
template< typename T > void operator()(T x)
{
result = result || (x == value);
}
int value;
bool& result;
};
template <class IntList>
bool isoneof(int val)
{
namespace mpl = boost::mpl;
bool result;
mpl::for_each<IntList>(Contains(val, result));
return result;
}
int main()
{
namespace mpl = boost::mpl;
std::cout << isoneof< mpl::vector_c<int, 1,2,3,5,7,11> >(4) << "\n";
std::cout << isoneof< mpl::vector_c<int, 1,2,3,5,7,11> >(5) << "\n";
}
As you can see, the compile-time array is passed inline as a template argument to isoneof.
This one?
int ints[] = {2,3,5,7,11};
#define ARRAY_SIZE(Array) (sizeof(Array)/sizeof((Array)[0]))
#define INLIST(x,array) isoneof(x,array,ARRAY_SIZE(array))
ADDITION:
template <typename T>
bool isoneof(const T& x, T *array, int n)
{
for(int i=0; i<n; ++i)
if(x==array[i])
return true;
return false;
}
Using C++11, this would be written like this:
template <typename T>
bool isoneof(T value, std::initializer_list<T> arr)
{
using namespace std;
return any_of(begin(arr), end(arr), [&](const T& x) { return x == value; });
}
Just FYI - I solved my particular problem using vararg templates and initializer lists now that I have access to C++14:
template <typename T, typename U>
bool isoneof(T v, U v1) { return v == v1; }
template <typename T, typename U, typename... Args>
bool isoneof(T v, U v1, Args ... others) { return isoneof(v, v1) || isoneof(v, others...); }
template <typename T, typename U>
bool isoneof(T value, std::initializer_list<U> values)
{
for (const auto & e : values)
if (value == e)
return true;
return false;
}