Topic: Selection Set proposal for C++ Template.


Author: jinhao<cnjinhao@hotmail.com>
Date: Mon, 24 Oct 2011 06:50:43 -0700 (PDT)
Raw View
Template is powerful, but it is hard to control. A new syntax proposal for controlling match of the template parameter.

template<typename T>
struct S<T = (int, char, double)>{};

S<int>  s_int;    //OK
S<char>  s_char;    //OK
S<double>  s_double; //OK
S<float>  s_float;    //Error, float is not allowed.

The part  T = (int, char, double) is a selection set.
----------------------------
The selection set used for explicit specialization.

template<typename T>
void foo(T);

template<typename T>
void foo<T = (A,B,C)>(T)
{
     //specialization for A, B, C, NOT overloading.
};

The part  T = (A, B, C) is a selection set, that means the fully matching one of class A, B and C for parameter T.

same as
----------------------------
template<typename T>
void foo_special_for_ABC(T)
{
     //specialization for A, B, C
}

template<>
void foo<A>(A a)
{
     foo_special_for_ABC(a);
}

template<>
void foo<B>(B b)
{
     foo_special_for_ABC(b);
}

template<>
void foo<C>(C c)
{
     foo_special_for_ABC(c);
}
---------------------



The selection set can support operator !
template<typename T>
void foo(T)
{
     //it indicates specilaizations for A,B,C
}

template<typename T>
void foo<T = !(A,B,C)>(T)
{
     //parameter T is not class A or B or C.
};

the operator ! also supports the following syntax.
template<typename T>
void foo<T = (!A, !B, !C)>(T)
{
     //the semantic is (not A || not B || not C),
     //in fact, T can be everything. It ambiguous with template<typename T>  foo(T)
     //and template<typename T>  void foo<T=!(A, B, C)>(T).
};

------------------------
Now, template is leak of matching template parameter by ralationship between classes.
We should fix this.

template<typename T>
void foo(T);

template<typename T>
void foo<T = :(B)>(T);    //<T=(:B)>
the opeartor: indicates a type that "is-a" B.

class D: public B{};
D d;
foo(d); //matchs template<typename T>  void foo<T = :(B)>(T);

This is a useful feature. Take a look at what problem I get.
-------------------------------------------------------------------------
class noncopyable
{
     noncopyable(const noncopyable&);
     noncopyable&  operator=(const noncopyable&);
public:
     noncopyable();
};

class B: private noncopyable;

//A creation functor used for some algorithms.
template<typename T>
struct creator
{
     template<typename Param>
     T * operator()(Param p)
     {
         return (new T(p));
     }


     T * operator()(B&  b)
     {
         return (new T(b));
     }
};

class C: public B
{
public:
     C(const B&);
};

class D: public B
{
public:
     D(int);
     D(const B&);
};

creator<C>  cc;
creator<D>  cd;
B b;
C * c = cc(b);    //OK
D * d1 = cd(1);    //OK
D * d2 = cd(*c);    //Error, call template<Param>  operator()(Param) that makes a copy of C, but the base of C is not copyable.
to fix it, we have to
D * d2 = cd(static_cast<B&>(*c));    //cast into B&  for matching operator()(B&)
or
D * d2 = cd.operator()<C&>(*c);    //explicitly specify the template parameter as a reference to avoid a copy.
These solutions make programer confused, and template class createor is a functor that we can't apply these solution in everywhere.
The second solution: modifying the template class creator by employing rvalue-reference.
template<typename T>
struct creator
{
     template<typename Param>
     T * operator()(Param&&  p)        //Here, so we can do D* d2 = cd(*c); with rvalue-reference. BUT
     {
         return (new T(p));
     }

     T * operator()(B&  b)
     {
         return (new T(b));
     }
};
But this is a trap, we will lose some information by employing rvalue-reference. what information?
     template<typename Param>
     T * operator()(Param p)
     {
         //...
     }
Param is not a reference, that we can determinate it whether a reference or a value by explicit specifying the template parameter. Such as
scanner s;
for_each<iterator, scanner&>(c.begin(), c.end(), s);
s.print_result();
----------------------------------------------------
A solution by using selection set.

template<typename T>
struct creator
{
     template<typename Param>
     T * operator()<Param = !(:B)>(Param p)
     {
         return (new T(p));
     }

     T * operator()(const B&  b)
     {
         return (new T(b));
     }
};
--------------------------------------------------
Regards,
Jinhao


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?=<daniel.kruegler@googlemail.com>
Date: Tue, 25 Oct 2011 10:01:49 -0700 (PDT)
Raw View
Am 24.10.2011 15:50, schrieb jinhao:
>  Template is powerful, but it is hard to control. A new syntax proposal for controlling match of the template parameter.

Your proposal looks like a special case of constraining templates. I
like the idea, but I would much more prefer, if this could be done
within a more general approach to define constrained templates, similar
to the approach that nearly came into C++11 (concept-based).

>  template<typename T>
>  struct S<T = (int, char, double)>{};

Given the concept approach of n2914 this could be defined as

template<IsIntCharDouble T>
struct S {};

which is a short form for

template<typename T>
requires IsIntCharDouble<T>
struct S {};

with a properly defined concept IsIntCharDouble. Of-course this is not
extensible and it would be useful to allow for a syntax like

template<typename T>
requires IsOneOf<T, int, char, double>
struct S {};

To give this a useful meaning, there most be some commonality for all
these types, e.g. all of them need to be refine the concept VariableType
or ObjectType.

My main criticism of your proposal is that it defines a complete new
meta language and it would be better to have it integrated into existing
grammar extensions like that of concepts.

HTH&  Greetings from Bremen,

Daniel Kr   gler





--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: Mathias Gaunard<loufoque@gmail.com>
Date: Wed, 26 Oct 2011 11:19:01 -0700 (PDT)
Raw View
On Oct 24, 3:50 pm, jinhao<cnjin...@hotmail.com>  wrote:
>  Template is powerful, but it is hard to control. A new syntax proposal for controlling match of the template parameter.
>
>  template<typename T>
>  struct S<T = (int, char, double)>{};

How is that significantly different from

template<class T, class Enable = void>
struct S;

template<class T>
struct S<T, typename enable_if<  contains<  vector<int, char, double>, T
>  >::type>
{
};


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: Jinhao<cnjinhao@hotmail.com>
Date: Thu, 27 Oct 2011 14:42:21 -0700 (PDT)
Raw View
On Oct 26, 1:01 am, Daniel Kr   gler<daniel.krueg...@googlemail.com>
wrote:
>  My main criticism of your proposal is that it defines a complete new
>  meta language and it would be better to have it integrated into existing
>  grammar extensions like that of concepts.

In my opinion, concepts is too complicated.

On Oct 27, 2:19 am, Mathias Gaunard<loufo...@gmail.com>  wrote:
>  How is that significantly different from

No difference, but the contrained templates can't work directly and
friendly with template functions.

such as, how the constrained templates make the demands so simply?
template<typename T>
struct creator
{
      template<typename Param>
      T * operator()<Param = !(:B)>(Param p) //Don't match this
template if Param is deduced that it is a type derived frome B.
      {
          return (new T(p));
      }

      T * operator()(const B&   b)
      {
          return (new T(b));
      }
};


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: Arne Mertz<arnemertz@googlemail.com>
Date: Sat, 29 Oct 2011 01:44:48 -0700 (PDT)
Raw View
On Oct 27, 11:42 pm, Jinhao<cnjin...@hotmail.com>  wrote:
>  No difference, but the contrained templates can't work directly and
>  friendly with template functions.
>

Could you explain that? I don't see any way that enable_if'd
templates, be it function or
class templates, could not do what you are proposing.

>  such as, how the constrained templates make the demands so simply?
>  template<typename T>
>  struct creator
>  {
>         template<typename Param>
>         T * operator()<Param = !(:B)>(Param p) //Don't match this
>  template if Param is deduced that it is a type derived frome B.
>         {
>             return (new T(p));
>         }

Looks like a completely new syntax, but is there any benefit that
justifies making
C++ Syntax yet more complicated? You'd need a bunch of syntax rules
just to
express the simpler cases for your template constrains, while concepts
have
simpler syntax rules but can be combined freely, because they are not
restricted
to be expressed inside the template parameter declaration. And I bet
there will be
a broad set of Concepts within the standard library to achieve any of
the standard
cases without adding any syntax rules (except the basic concepts
rules).

As for your example, it can easily be achieved with today's standard
library:

template<typename Param>
std::enable_if<  !std::is_base_of<B, Param>::value,
T*>::type operator*(Param p)
{
   return (new T(p));  //perhaps even better: perfect forwarding of p?
}

granted, its longer than your example, but for now it's readable, and
with Concepts
it might become something like

template<IsNotDerivedFrom<B>  Param>
T* operator*(Param p)

or something similar - with the concept provided by the standard
library.


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]