Recursive concept usgae

79 views
Skip to first unread message

Sergey Strukov

unread,
May 17, 2016, 5:44:31 AM5/17/16
to SG8 - Concepts
template <class T>
struct PrintableTupleTypeCtor
 
{
 
enum RetType { Ret = false };
 
};


template <class T>
concept bool PrintableType = (bool)PrintableTupleTypeCtor<T>::Ret || requires(PrintBase &out,const T &t)
 
{
 
PrintAdapter<T>::Print(out,t);
 
} ;


template <PrintableType ... TT>
struct PrintableTupleTypeCtor<Tuple<TT...> >
 
{
 
enum RetType { Ret = true };
 
};


Is this trick legal? OR, at least should it be legal?

It is working on gcc-6.1.0, but not recursively.

Andrew Sutton

unread,
May 17, 2016, 8:20:23 AM5/17/16
to SG8 - Concepts
Looks legal to me. 

Is it failing on a tuple of tuples?


--
You received this message because you are subscribed to the Google Groups "SG8 - Concepts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to concepts+u...@isocpp.org.
To post to this group, send email to conc...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/concepts/.
--
Andrew Sutton

Sergey Strukov

unread,
May 17, 2016, 10:01:53 PM5/17/16
to SG8 - Concepts
I have prepared a full test for your convenience.

/* main.cpp */

#include <iostream>

using namespace std;

/* struct Fold<TT> */

template <class ... TT> struct Fold;

/* concept TestInt<T> */

template <class T>
struct IntFoldCtor

 
{
 
enum RetType { Ret = false };
 
};

template <class T>
concept bool TestInt = (bool)IntFoldCtor<T>::Ret || is_same<T,int>::value ;

template <TestInt ... TT>
struct IntFoldCtor<Fold<TT...> >

 
{
 
enum RetType { Ret = true };
 
};

/* main() */

int main()
 
{
  cout
<< TestInt<int> << endl ; // 1

  cout
<< TestInt<short> << endl ; // 0

  cout
<< TestInt< Fold<int,int,int> > << endl ; // 1

  cout
<< TestInt< Fold<int,int,short> > << endl ;  // 0

 
cout << TestInt< Fold<int,Fold<int,int>,int> > << endl ; // 0

  cout
<< TestInt< Fold<int,Fold<int,short>,int> > << endl ; // 0

  cout
<< TestInt< Fold<int,Fold<int,int>,short> > << endl ; // 0

 
return 0;
 
}



On Tuesday, May 17, 2016 at 3:20:23 PM UTC+3, Andrew Sutton wrote:
Looks legal to me. 

Is it failing on a tuple of tuples?


--
Andrew Sutton
 

Tom Honermann

unread,
May 18, 2016, 10:36:35 AM5/18/16
to conc...@isocpp.org
Your test case looks well-formed to me, but I defer to Andrew.   Assuming he doesn't disagree, I suggest you file a bug at https://gcc.gnu.org/bugzilla.  Prefix the bug summary with "[concepts]".

I was able to get the code to work as I think you want it to with a minor change to the IntFoldCtor partial specialization.  Instead of using the concept as a constrained-type-specifier, I used a C++17 fold expression to compute the Ret enumerator value.


/* main.cpp */

#include <iostream>

using namespace std;

/* struct Fold<TT> */

template <class ... TT> struct Fold;

/* concept TestInt<T> */

template <class T>
struct IntFoldCtor
 {
  enum RetType { Ret = false };
 };

template <class T>
concept bool TestInt =  (bool)IntFoldCtor<T>::Ret || is_same<T,int>::value ;

template <typename ... TT>
struct IntFoldCtor<Fold<TT...> >
 {
  enum RetType { Ret = (TestInt<TT> && ...) };

 };

/* main() */

int main()
 {
  cout << TestInt<int> << endl ; // 1

  cout << TestInt<short> << endl ; // 0

  cout << TestInt< Fold<int,int,int> > << endl ; // 1

  cout << TestInt< Fold<int,int,short> > << endl ;  // 0

  cout << TestInt< Fold<int,Fold<int,int>,int> > << endl ; // Was 0, now 1


  cout << TestInt< Fold<int,Fold<int,short>,int> > << endl ; // 0

  cout << TestInt< Fold<int,Fold<int,int>,short> > << endl ; // 0

  return 0;
 }


Tom.

Casey Carter

unread,
May 18, 2016, 12:47:22 PM5/18/16
to SG8 - Concepts
template <class ... TT> struct Fold;


template <class>
constexpr bool IntFoldCtor = false;
template <>
constexpr bool IntFoldCtor<int> = true;


template <class T>
concept bool TestInt = IntFoldCtor<T>;


template <TestInt ... TT>
constexpr bool IntFoldCtor<Fold<TT...>> = true;


static_assert( TestInt<int>);
static_assert(!TestInt<short>);
static_assert( TestInt<Fold<int,int,int>>);
static_assert(!TestInt<Fold<int,int,short>>);
static_assert( TestInt<Fold<int,Fold<int,int>,int>>);
static_assert(!TestInt<Fold<int,Fold<int,short>,int>>);
static_assert(!TestInt<Fold<int,Fold<int,int>,short>>);


int main() {}


I suspect the bug is an interaction between disjunction and variadic concept application. (As an aside, it's a good idea in general to avoid disjunctions in concept definitions. They can have catastrophic performance consequences in the current GCC implementation of concepts.)
Reply all
Reply to author
Forward
0 new messages