struct MyType : std::string {
using string::string;
};
class Address using public std::string {
public:
};
Note that there is no need to add forward constructors as the using
keyword would intend already to have the same interface as the
underlying type. Address
should not be seen implicitly as a
std::string the using should be privateclass Address using private std::string {
// possibility to add new member functions
};
class Temperature using double {
// possibility to add new member functions
};
struct
Address
using std::string { std::size_t length() const = delete; };
One question is whether the new class can add new data members. I don't think tis is a good idea the new type and the underlying type should have the same size.
An alternative could be to use a new keyword (e.g. alias) so that this constraint is clearer.
alias
Address
using
std::string {
std::size_t length() const = delete;
};
#include <vector>
using A = int;
using explicit B = int;
template<typename T> using C = std::vector<T>;
template<typename T> using explicit D = std::vector<T>;
int main()
{
int n = 0;
std::vector<int> v = { 1, 2, 3 };
A a = n; // Implicit conversion
B b = n; // Error, no implicit conversion
C<int> c = v; // Implicit conversion
D<int> d = v; // Error, no implicit conversion
}
using A = int;
using class B = int;
template<typename T> using C = std::vector<T>;
template<typename T> using class D = std::vector<T>;
On Monday, November 19, 2012 6:59:15 PM UTC-8, Martin Desharnais wrote:Alternativly, the alias declaration could be expand to support the explicit specifier:
#include <vector>
using A = int;
using explicit B = int;
template<typename T> using C = std::vector<T>;
template<typename T> using explicit D = std::vector<T>;
int main()
{
int n = 0;
std::vector<int> v = { 1, 2, 3 };
A a = n; // Implicit conversion
B b = n; // Error, no implicit conversion
C<int> c = v; // Implicit conversion
D<int> d = v; // Error, no implicit conversion
}
I think that would be consistent with explicit constructor and explicit conversion operator in that it disallow implicit conversion but stil let the programmer explicitly ask it.
I like the syntax here, particularly only allowing it with the new `using` syntax instead of the old `typedef`.
However, `enum class` already does something similar with enumerators. So we might want to use syntax like that instead of `explicit`:
using A = int;
using class B = int;
template<typename T> using C = std::vector<T>;
template<typename T> using class D = std::vector<T>;
Admittedly that's bikesheding. I do like the `class` being there, which helps show that you're not creating a type alias but a new type.
Le 20/11/12 04:41, Nicol Bolas a écrit :
On Monday, November 19, 2012 6:59:15 PM UTC-8, Martin Desharnais wrote:Alternativly, the alias declaration could be expand to support the explicit specifier:
#include <vector>
using A = int;
using explicit B = int;
template<typename T> using C = std::vector<T>;
template<typename T> using explicit D = std::vector<T>;
int main()
{
int n = 0;
std::vector<int> v = { 1, 2, 3 };
A a = n; // Implicit conversion
B b = n; // Error, no implicit conversion
C<int> c = v; // Implicit conversion
D<int> d = v; // Error, no implicit conversion
}
I think that would be consistent with explicit constructor and explicit conversion operator in that it disallow implicit conversion but stil let the programmer explicitly ask it.
I like the syntax here, particularly only allowing it with the new `using` syntax instead of the old `typedef`.
Yes unifying proposals would be great. Please, could you point me to the new using proposal?
One of the major concerns of the Opaque proposals was to make the following difference:However, `enum class` already does something similar with enumerators. So we might want to use syntax like that instead of `explicit`:
using A = int;
using class B = int;
template<typename T> using C = std::vector<T>;
template<typename T> using class D = std::vector<T>;
Admittedly that's bikesheding. I do like the `class` being there, which helps show that you're not creating a type alias but a new type.
Opaque typedef are explicitly convertible to the underlying type. But are they implicitly convertible? It depends.How the new syntax could take in account this point?
- public opaque : implicit conversion to the underlying type
- private opaque : explicit conversion to the underlying type
Does the new using proposal allows to add new function members?
--
I'm not sure I understand why you think my suggestion of using inheriting constructorsprevents adding member functions. I was simply highlighting that inheriting constructorscould emulate a solution if the user chose to use them in such a simple/restricted way.Nothing prevents the addition of more function (or data!) members, and we do not need anew syntax to support that.
Among the known reasons that inheriting constructors do not solve Walter's originalproblem are that they cannot be used for the following types:fundamental typesaggregate classesarraysunionsfinal classesenumerationspointerspointer-to-memberscv-qualified typesfunction typesincomplete types
There may well be some more type categories that I missed, but those are the onesthat I am immediately aware of. We may not want such a feature to support *all* ofthese cases, but this would be my primary motivation for adding a new languagefeature to support Walter's original proposal - and I will not be writing that papermyself ;~)
On Monday, November 19, 2012 11:04:28 PM UTC-8, viboes wrote:
Le 20/11/12 04:41, Nicol Bolas a écrit :
On Monday, November 19, 2012 6:59:15 PM UTC-8, Martin Desharnais wrote:
Alternativly, the alias declaration could be expand to support the explicit specifier:
I think that would be consistent with explicit constructor and explicit conversion operator in that it disallow implicit conversion but stil let the programmer explicitly ask it.
I like the syntax here, particularly only allowing it with the new `using` syntax instead of the old `typedef`.
Yes unifying proposals would be great. Please, could you point me to the new using proposal?
It's not a proposal; that's standard C++11. You can use it for templates (which was the primary purpose), but it also can do everything that `typedef` could. And with much nicer syntax.
I see. I thought alias were reserved
to templates.
One of the major concerns of the Opaque proposals was to make the following difference:However, `enum class` already does something similar with enumerators. So we might want to use syntax like that instead of `explicit`:
using A = int;
using class B = int;
template<typename T> using C = std::vector<T>;
template<typename T> using class D = std::vector<T>;
Admittedly that's bikesheding. I do like the `class` being there, which helps show that you're not creating a type alias but a new type.
Opaque typedef are explicitly convertible to the underlying type. But are they implicitly convertible? It depends.How the new syntax could take in account this point?
- public opaque : implicit conversion to the underlying type
- private opaque : explicit conversion to the underlying type
Does the new using proposal allows to add new function members?
It depends entirely on exactly what problems you're trying to solve. The one that Martin and I were solving was the ability to create an exact duplicate of a type, only with a different name. This is also the problem N1891 and N2141 are focused on solving.
using A = int; // equivalent to a typedef, that is no new
type
using class B = int; // a new type with explicit conversion to
int?
using struct B = int;
// a new type with implicit conversion
to int?
Adding new function members is outside the scope of solving that problem.
Yes but how the alias syntax allows to make a difference between implicit/explicit conversions to the underlying type? Do you want to mean a different things with
using A = int; // equivalent to a typedef, that is no new type
using class B = int; // a new type with explicit conversion to int?
using struct B = int;
// a new type with implicit conversion to int?
enum class A { a, b, c };
enum struct A { a, b, c }; // Error, multiple definition of ‘enum class A’
Yes but how the alias syntax allows to make a difference between implicit/explicit conversions to the underlying type? Do you want to mean a different things with
using A = int; // equivalent to a typedef, that is no new type
using class B = int; // a new type with explicit conversion to int?
using struct B = int;
// a new type with implicit conversion to int?
You are right that using "class/struct" specifier instead of "explicit" bring that question but, fortunatly, it have already been solved by "enum":
enum class A { a, b, c };
enum struct A { a, b, c }; // Error, multiple definition of �enum class A�
The same rule would apply with the extend alias directive.
enum class and enum struct are equivalent. So I think that using them for strongly types with a different semantics will not be coherent. I guess that we need to find out some keywords to mean EXPLICT or IMPLICIT conversion or something else.
using
A = int; //
equivalent to a typedef, that is, no new type
using B = EXPLICIT int;
// a new type with explicit conversion to int?
using C = IMPLICIT int;
// a new type with implicit conversion
to int?
using A = int; // equivalent to a typedef, that is, no new type
using B = EXPLICIT int; // a new type with explicit conversion to int?
using C = IMPLICIT int;
// a new type with implicit conversion to int?
-- Vicente
using new C = int;
// a new type with implicit conversion to int?
I think this is the better choice. Having new T is just too confusing- people will start trying to declare variables that way.
By the way, it looks like a simple feature, but I have some reservations.
One of them is connected to fundamental types, ability to have new fundamental type unrelated to other fundamental types is a breaking change.Other is about base classes. For example:using new A = B;What relation A has to base classes of B? What if we have virtual inheritance in the bases of B?
By the way, it looks like a simple feature, but I have some reservations.One of them is connected to fundamental types, ability to have new fundamental type unrelated to other fundamental types is a breaking change.
Other is about base classes. For example:using new A = B;What relation A has to base classes of B? What if we have virtual inheritance in the bases of B?
Third is about explicit template specializations. We have explicit specialization for A, but none for B. Should we consider specialization for A as specialization for B?
Here's an expanded version.
Given two template instantiations, one with OT [opaque type] as a template argument and the other with UT [underlying type] as the corresponding argument, how are the instantiations related?
Proposed answer: the two instantiations are unrelated.
Now, without opaque typedefs it was possible to write specializations for all floating point types or for all integer types, with opaque typedefs given that answer it would no longer be possible.
Moreover while N1891 states that all standard properties of type (exposed via type-traits) are the same for OT and UT, it also implies that OT does not keep non-standard properties of UT (like iterator traits), as these properties are defined via template specializations.
e.g. following is not possible
using new IntPtr = int*;
int arr[10] = {1,2,...};
std::accumulate((IntPtr)arr, (IntPtr)arr + 10);
It seems, that keeping non-standard properties is desirable. It is also desirable to have different specializations for UT and OT.
Regards,
Gregory
Now, without opaque typedefs it was possible to write specializations for all floating point types or for all integer types, with opaque typedefs given that answer it would no longer be possible.
Are the opaque types classes?
[1] says that the type traits of the OT are defined as the ones of the underlying type, is_TRAIT<OT> = is_TRAIT<UT>.
So if we have
using class C = int;
is_class<C> should be false_type. This should be a little bit confusing, but there is an antecedent as an enum class is not a class.
I would prefer that opaque types be classes independently of the underlying types but maybe there are some issues with the core language.
Does the opaque type inherits from all the template classes specialized with the underlying type?
Which are the operations an opaque type provides?
Should the user be able to define opaque types providing less functions than its underlying type?
I would say yes, but then the alias statement should be extended in some way.
Sorry if my comment will pointless and early discussed, but…
Why instead extending ‘using’ not allow just have non-class types as class parent types so have:
class C : private int { … }
or
class S : public int { … }
That directly allow easy define interface of new type and provide same implicit/explicit difference new type from original type
Using existed C++ syntax features.
Vladimir
From: Vicente J. Botet Escriba [mailto:vicent...@wanadoo.fr]
Sent: Thursday, November 22, 2012 2:00 AM
To: std-pr...@isocpp.org
Subject: Re: [std-proposals] Re: N1891: Progress toward Opaque Typedefs for C++0X
Should the user be able to define opaque types providing less functions than its underlying type?
I would say yes, but then the alias statement should be extended in some way.
Before analyzing more deeply these subjects in order to make a concrete proposal I would like to have some feedback. Maybe all this is already clear for some of you and I'm missing something evident.
Best,
Vicente
[1] N1891: Progress toward Opaque Typedefs for C++0X
--
Which are the operations an opaque type provides?
An opaque type having a builtin type as underlying type should provide the same operations than the builtin type. It is less clear when the base type is a defined type.
I would say that the opaque type provides at least all the member functions defined by the underlying type or by its base classes. But what about the non-member functions that have as one of its parameters the underlying type? Providing all these functions will imply an implicit conversion of the opaque type to the underlying type. So if the opaque type should provide a subset of these functions we need a mechanism to identify them. Now that there are more and more types that define its interface using non-members functions I would say that there is a need to 'inherit' from some of these functions.
I see two alternatives, either we identify them when defining the opaque type, or when defining the underlying type.
I'm for the last alternative and IMO, we need a language mechanism to identify the inherent operations of an underlying type which will be the ones provided by an associated opaque type.
I still have to write a proposal for named operators, but I believe that they solve that problem for new code.
--
I still have to write a proposal for named operators, but I believe that they solve that problem for new code.
Sorry if my comment will pointless and early discussed, but…
Why instead extending ‘using’ not allow just have non-class types as class parent types so have:
class C : private int { … }
or
class S : public int { … }
That directly allow easy define interface of new type and provide same implicit/explicit difference new type from original type
Using existed C++ syntax features.
Some feedback :
On Wed, Nov 21, 2012 at 10:59 PM, Vicente J. Botet Escriba <vicent...@wanadoo.fr> wrote:
Are the opaque types classes?
[1] says that the type traits of the OT are defined as the ones of the underlying type, is_TRAIT<OT> = is_TRAIT<UT>.
So if we have
using class C = int;
is_class<C> should be false_type. This should be a little bit confusing, but there is an antecedent as an enum class is not a class.
I would prefer that opaque types be classes independently of the underlying types but maybe there are some issues with the core language.
I can understand that enum class cannot be considered the same way than a class.However, here the feature is, as far as I understand it, supposed to "clone perfectly" the right-side type, which would imply that
is_class<C>::value == is_class<int>::value
Because otherwise I don't see the point of this feature.
Does the opaque type inherits from all the template classes specialized with the underlying type?
As I said, i don't see the point if the generated type isn't an exact clone.
Which are the operations an opaque type provides?
Same logic for me: it should just be a type clone.
Should the user be able to define opaque types providing less functions than its underlying type?
I would say yes, but then the alias statement should be extended in some way.
I don't see any use case for this. Do you have one? (I might miss something here).
Le 22/11/12 10:58, grigor...@gmail.com a écrit :
Hi,I still have to write a proposal for named operators, but I believe that they solve that problem for new code.
could you elaborate on how your future named operator proposal will address the mentioned problems?
Vicente
Четвер, 29 листопада 2012 р. 19:06:16 UTC+2 користувач viboes написав:Le 22/11/12 10:58, grigor...@gmail.com a écrit :
Hi,I still have to write a proposal for named operators, but I believe that they solve that problem for new code.
could you elaborate on how your future named operator proposal will address the mentioned problems?
VicenteNamed operator is a free function declared with operator keyword.A operator fun(const A& a);Such functions should be considered as a part of an interface of its first (?) parameter.
class A{};
std::ostream& operator<<(std::ostream&, A const&);
Четвер, 29 листопада 2012 р. 19:06:16 UTC+2 користувач viboes написав:Le 22/11/12 10:58, grigor...@gmail.com a écrit :
Hi,I still have to write a proposal for named operators, but I believe that they solve that problem for new code.
could you elaborate on how your future named operator proposal will address the mentioned problems?
VicenteNamed operator is a free function declared with operator keyword.A operator fun(const A& a);Such functions should be considered as a part of an interface of its first (?) parameter.That gives us a way to distinguish between usual free functions and free functions coupled to the class.
I agree as far as there is no mechanism to extend the opaque type with new operations.
Let me show an example. I can define a meta-function that tells if two classes belong to the same domain.
template <typename T, typename U>
struct same_domain : false_type {};
template <>
struct same_domain<A,B> : true_type{};
If I define a new opaque type
using class C = A;
should be same_domain<C,B> a true_type or false_type?
By clone I understand that it is a different type.
Which are the operations an opaque type provides?
Same logic for me: it should just be a type clone.
class A;
A& operator+(A const&,A const&);
using class C = A;
Could I expect the following to be valid
C c;
c = c + c ;
Named operators allow strict definition of extended interface of a class. That notion is useful not only for opaque aliases. I started thinking about it when I read ADL Control for C++.There was proposed to have an option to disable ADL for all non-operator names in the current scope except for those that are mentioned in a special using directive. In my opinion it was okay to disable ADL for most of the functions, however not for those that are connected to a class, and those may be usual functions not only operators.So, my initial idea was to have named operators proposal as addendum to the N3490.
If we stop here, then named operators are just specially declared free functions and are called as such:func(a,b);oroperator func(a,b);But there was another idea - to open-up classes in C++, that is to allow a limited form of partial classes of C#/VB - allow additional definitions of class that contain typedefs and members. It seems with using aliases we on a longer term will not need inner typedefs anyway, but adding new non-virtual functions to exiting class may be beneficial - with that we would have a sort of concept maps for non-generic code.That is possible if we allow named operators to be called like members. That is the second part of the proposal. There are unsolved problems however, it is tempting to have an ability to overload existing member-function with named operator, but member-function if it matches parameters should always be considered as better match than named operator, that leads to more complicated matching procedure...Anyway, with second part of the proposal named operators may be called as member functions:a.func(b);
I don't understand the rationale of why is needed to make a difference for operators in N3490.
IIUC your idea, the trouble I see with your named operators applied to strong types is that the inherited interface is open and depends on which files are you seen. The same applies to the open-up classes proposal. I really think that we nedd a single point on which non-member functions are added to the set of inherited functions.
О©ҐО©ҐО©ҐО©ҐО©ҐО©Ґ, 8 О©ҐО©ҐО©ҐО©ҐО©ҐО©Ґ 2012 О©Ґ. 15:29:50 UTC+2 О©ҐО©ҐО©ҐО©ҐО©ҐО©ҐО©ҐО©ҐО©ҐО©Ґ viboes О©ҐО©ҐО©ҐО©ҐО©ҐО©ҐО©Ґ:
I don't understand the rationale of why is needed to make a difference for operators in N3490.
I believe I understand it now.The main reason for introducing ADL was to keep the expected behavior for operators in the presence of namespaces. N3490 tries to get ADL right, that is to turn it off for those functions that are never inteded to be found by ADL, but keep it for functions that should be found by ADL (operators).О©ҐО©ҐО©Ґ
IIUC your idea, the trouble I see with your named operators applied to strong types is that the inherited interface is open and depends on which files are you seen. The same applies to the open-up classes proposal. I really think that we nedd a single point on which non-member functions are added to the set of inherited functions.
I understand the point of N1742. What I mean is that I'm not sure all the new member-functions added to the underlying type (using N1742) should be inherited by the strong type. Or are you suggesting that the user should use the N1742 mechanism to extend the operations on the Strong type?Why do you consider this as a trouble? Opening-up classes, that is allowing to add new member-functions to existing classes in non-intrusive way was the whole point of N1742.О©Ґ
I understand the point of N1742. What I mean is that I'm not sure all the new member-functions added to the underlying type (using N1742) should be inherited by the strong type. Or are you suggesting that the user should use the N1742 mechanism to extend the operations on the Strong type?
In addition, the N1742 mechanism doesn't covers all the operations a strongly type could inherit from, as it forces to change the call syntax of the inherited function.
Субота, 8 грудня 2012 р. 15:29:50 UTC+2 користувач viboes написав:I don't understand the rationale of why is needed to make a difference for operators in N3490.The main reason for introducing ADL was to keep the expected behavior for operators in the presence of namespaces. N3490 tries to get ADL right, that is to turn it off for those functions that are never inteded to be found by ADL, but keep it for functions that should be found by ADL (operators).
Just one clarification here. Perhaps a bit off topic. While operators might have been the primary motivation for ADL, non-operator functions also now depend on it. The example I have in mind is swap(), which in a way has something of an operator.
Hi,
there is an old proposal [1] from Walter E. Brown about opaque types that I have found quite interesting.
One of the motivating examples is the ability to overload on these new types
typedef public double X, Y, Z; // Cartesian 3D coordinate types
typedef public double Rho, Theta, Phi; // polar 3D coordinate types
class PhysicsVector
{
public:
PhysicsVector(X, Y, Z);
PhysicsVector(Rho, Theta, Phi);
...
}; // PhysicsVector
Could some one tell me if the committee was interested on this proposal? Is there a plant to resurrect it?
Alisdair Meredith showed in [2] that forward constructor could help on this but that there are some issues that are not addressed by this construction.
struct MyType : std::string { using string::string; };
I'm wondering if the syntax couldn't be adapted so that the new type could contain more function members.
Note that there is no need to add forward constructors as the using keyword would intend already to have the same interface as the underlying type.class Address using public std::string { public: };
IfAddress
should not be seen implicitly as a std::string the using should be private
class Address using private std::string { // possibility to add new member functions };
Note that builtin types could also be used as underlying types as it is the case of the Opaque typedef proposal.
class Temperature using double { // possibility to add new member functions };
By default the new type has the same operations than the underlying type. Restricting the interface of the underlying type should also be possible if the operation is decorated with delete.
struct
Address
using std::string { std::size_t length() const = delete; };One question is whether the new class can add new data members. I don't think tis is a good idea the new type and the underlying type should have the same size.
An alternative could be to use a new keyword (e.g. alias) so that this constraint is clearer.
alias
Address
using std::string {
std::size_t length() const = delete;
};
Is there some interest?
class Energy : public double
{
// possibly override operators, add user-defined literals, etc.
// Otherwise have all arithmetic operators and I/O because of public derivation from double.
};
> For private inheritance, we would need to explicitly reintroduce> the operators, perhaps with =default.wouldn't it be via 'using', like you do normally for pulling base
functions into derived space?
I guess the syntax might be:
using double::operator*;
> I don't think this extra
> work is necessarily a bad thing, because Energy*Energy is not Energy.