std::any augumentation

609 views
Skip to first unread message

jane...@gmail.com

unread,
Mar 2, 2017, 1:26:01 PM3/2/17
to ISO C++ Standard - Future Proposals
I believe that std::any should be made invokable, if an invokable object is stored into it, such as a function pointer, method pointer, or a functor (such as std::function<> and others). This would raise the level of abstraction C++ offers to one comparable to scripting languages, where you can often invoke an arbitrary variable. I've prepared 2 examples:


These examples are built around a std::any lookalike, but their functionality could be easily merged into a std.:any, asserts could be substituted for exception throwing and other changes made to make it more std:: palatable.

Klaim - Joël Lamotte

unread,
Mar 2, 2017, 1:31:24 PM3/2/17
to std-pr...@isocpp.org
Interesting. How would that be compared to recent unique_function and function modification proposals?

Joël Lamotte


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c6fbbdcd-b9fb-475e-863b-0582a771ed2c%40isocpp.org.

janezz55 .

unread,
Mar 2, 2017, 1:37:52 PM3/2/17
to std-pr...@isocpp.org
I don't think the proposals would affect mine in any way. My goal is to raise the level of abstraction, not provide a solution to some problem.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Mar 2, 2017, 2:41:33 PM3/2/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Thursday, March 2, 2017 at 1:26:01 PM UTC-5, jane...@gmail.com wrote:
I believe that std::any should be made invokable, if an invokable object is stored into it, such as a function pointer, method pointer, or a functor (such as std::function<> and others). This would raise the level of abstraction C++ offers to one comparable to scripting languages, where you can often invoke an arbitrary variable.

But the purpose of `any` isn't to be "comparable to scripting languages". It's for being able to store an object of any (copyable) type and be able to retrieve it in a type-safe way. It's a type-safe `void*` with value semantics.

Adding a function interface to it doesn't help `any` achieve the goal it's setting out to achieve.

If you want to suggest a type that can store any callable and attempt to call it with any arbitrary sequence of parameters and return types (throwing an exception if the given params/return value doesn't match), that's a different type from `any`.

janezz55 .

unread,
Mar 2, 2017, 3:15:03 PM3/2/17
to std-pr...@isocpp.org
From my perspective, the user could easily ignore, that std::any is invokable. I believe that adding a separate class, which would duplicate a lot of what std::any does, would not reflect well on the STL.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Brian Bi

unread,
Mar 2, 2017, 3:29:13 PM3/2/17
to std-pr...@isocpp.org
On Thu, Mar 2, 2017 at 12:15 PM, janezz55 . <jane...@gmail.com> wrote:
From my perspective, the user could easily ignore, that std::any is invokable. I believe that adding a separate class, which would duplicate a lot of what std::any does, would not reflect well on the STL.

It's all a question of your attitude toward C++. Do you want C++ to be like a scripting language or do you want it to be a language where the type system catches mistakes for you at compile time?

In my opinion, making a class that either does or doesn't do something when called, depending on what you put inside it, without any way for the compiler to check, would not reflect well on C++.
 

2017-03-02 20:41 GMT+01:00 Nicol Bolas <jmck...@gmail.com>:
On Thursday, March 2, 2017 at 1:26:01 PM UTC-5, jane...@gmail.com wrote:
I believe that std::any should be made invokable, if an invokable object is stored into it, such as a function pointer, method pointer, or a functor (such as std::function<> and others). This would raise the level of abstraction C++ offers to one comparable to scripting languages, where you can often invoke an arbitrary variable.

But the purpose of `any` isn't to be "comparable to scripting languages". It's for being able to store an object of any (copyable) type and be able to retrieve it in a type-safe way. It's a type-safe `void*` with value semantics.

Adding a function interface to it doesn't help `any` achieve the goal it's setting out to achieve.

If you want to suggest a type that can store any callable and attempt to call it with any arbitrary sequence of parameters and return types (throwing an exception if the given params/return value doesn't match), that's a different type from `any`.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c138266b-9523-41ce-a601-3579a675eab2%40isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Mar 2, 2017, 3:40:30 PM3/2/17
to ISO C++ Standard - Future Proposals


On Thursday, March 2, 2017 at 3:29:13 PM UTC-5, Brian Bi wrote:
On Thu, Mar 2, 2017 at 12:15 PM, janezz55 . <jane...@gmail.com> wrote:
From my perspective, the user could easily ignore, that std::any is invokable. I believe that adding a separate class, which would duplicate a lot of what std::any does, would not reflect well on the STL.

It's all a question of your attitude toward C++. Do you want C++ to be like a scripting language or do you want it to be a language where the type system catches mistakes for you at compile time?

In my opinion, making a class that either does or doesn't do something when called, depending on what you put inside it, without any way for the compiler to check, would not reflect well on C++.

But... that's what `any` is.

If you do an `any_cast`, the compiler doesn't check if it's right. Because it cannot check to see if the `any` is the right type. That's the entire point of the class: it does a runtime check.

He's asking that `any` extend this runtime type checking to function calls, presumably throwing if the parameter list/return value is inappropriate. I'm saying that we should have a type specifically intended for that purpose.

janezz55 .

unread,
Mar 2, 2017, 3:57:46 PM3/2/17
to std-pr...@isocpp.org
Exactly, the throwing can happen at runtime with the unaugmented std::any as well. The abstraction level of C++ has been increasing steadily, reaching the abstraction levels of scripting languages is only a question of time. You must have noticed that ever more scripting languages have compilers nowadays as well?

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Mar 2, 2017, 4:01:50 PM3/2/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Thursday, March 2, 2017 at 3:15:03 PM UTC-5, janezz55 . wrote:
From my perspective, the user could easily ignore, that std::any is invokable.

Can they? Can you provide an implementation of an invokable `any` which has the exact same overhead as a non-invokable one, so long as you don't actually use the invoking interface?

I'm not saying you're wrong, but as someone who is not an expert on `any` implementations, I have my doubts about this statement.

I believe that adding a separate class, which would duplicate a lot of what std::any does, would not reflect well on the STL.

It would duplicate some of the the internals of `any`. But being a different type woudl demonstrate a different semantic meaning to code.

Let's rename `any` to `any_object`. Now let's talk about `any_object` in relation to what you want, which is `any_function`.

What does `any_object` represent, semantically? It represents an implicit agreement between the writer of the function taking the `any` and the person providing the value. Both sides must agree on what type(s) that `any_object` will store, and if there is a disagreement or if one side does the wrong thing, exceptions will fly.

What does your conceptual `any_function` represent, semantically? It represents, not the type-erasure of a value, but the type-erausre of a function call signature. And therefore, if you see a function that takes a parameter of type `any_function`, you immediately know that this function will call the given object.

And therefore, the agreement between us is different. The agreement is not that I will provide one or more implicitly-defined types that you will eventually `any_cast` to. The agreement is that I will provide objects that can be called with one or more implicitly-defined function call signatures, that you will eventually call.

If they represent different agreements, then they clearly should be different types. Even if 99% of the code implementation between them is identical, they still need to be separate. Because the code that takes an `any_function` does not want to perform `any_cast` on the value it takes. It will perform `any_call` instead. And vice-versa: code that takes `any_object` will not perform `any_call` on it.

I wouldn't mind having this in the `<any>` header. But I don't like the idea of grafting such a substantially different use case into an existing object.

Also, a pedantic note. "STL" does not mean "standard library."

janezz55 .

unread,
Mar 2, 2017, 4:13:12 PM3/2/17
to ISO C++ Standard - Future Proposals
I can tell you as an any semi-expert, that std::any, such as it is, is a resource hog. It mostly allocates from the heap to copy or move an object into it, of course small object optimizations are possible ..., but let's leave that on the side. The only argument to merge this functionality into std::any is because I think invocations of std::any are a "natural" extension of what std::any does, as you can see in almost any scripting language, like lus, python, perl... Using SFINAE and perhaps other techniques you can easily morph a std::any into std::any_function and vice versa. You can have 2 separate types, essentially, without the user knowing anything about it.

Nicol Bolas

unread,
Mar 2, 2017, 4:38:25 PM3/2/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Thursday, March 2, 2017 at 4:13:12 PM UTC-5, janezz55 . wrote:
I can tell you as an any semi-expert, that std::any, such as it is, is a resource hog. It mostly allocates from the heap to copy or move an object into it, of course small object optimizations are possible ..., but let's leave that on the side. The only argument to merge this functionality into std::any is because I think invocations of std::any are a "natural" extension of what std::any does, as you can see in almost any scripting language, like lus, python, perl...

But they're only a "natural extension" if you're making a type which is trying to mimic the behavior of scripting language types. And that's not really the purpose of `any`.

If you want to have more comprehensive support for duck typing in C++, then that's something which should happen in another way.

Using SFINAE and perhaps other techniques you can easily morph a std::any into std::any_function and vice versa. You can have 2 separate types, essentially, without the user knowing anything about it.

And why is it a good thing to not have the user know what they're doing?

C++ has plenty of places where the meaning of a piece of syntax is indeterminate. Is it legal to pass NULL for a particular `T*` parameter, or are you just passing a pointer because its convenient? Are you transferring ownership with a `T*` parameter, or is it just viewing the object? Is it a pointer to a single object or an array of some size?

We shouldn't add more of these cases where the semantic meaning of a parameter is indeterminate. There is a semantic difference between functions that take `any_object` and `any_function`, so they should be distinct types.

Brian Bi

unread,
Mar 2, 2017, 4:38:39 PM3/2/17
to std-pr...@isocpp.org
Right---std::any_cast represents the "ugly" aspect of std::any. But std::any is provided for those few users who really do need it. But we should avoid making it any more ugly than it already is. I agree that there should be a separate type. Users should not be forced to use std::any if it provides more ugliness than they actually need. :-)

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 2, 2017, 4:50:46 PM3/2/17
to ISO C++ Standard - Future Proposals
I think that perhaps the strongest argument in favor of a single type is the stored function's return value. It has to be stored in a std::any itself. I would consider invoking a std::any_function and getting a std::any as a return value very confusing.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Ren Industries

unread,
Mar 2, 2017, 5:43:03 PM3/2/17
to std-pr...@isocpp.org

Nicol Bolas

unread,
Mar 3, 2017, 1:15:04 AM3/3/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Thursday, March 2, 2017 at 4:50:46 PM UTC-5, janezz55 . wrote:
I think that perhaps the strongest argument in favor of a single type is the stored function's return value. It has to be stored in a std::any itself.

Nonsense:

template<typename ReturnType, typename ...Args>
ReturnType any_call(any_function, Args &&...params);

Just as you specify the parameter types to use, you must also specify the return type. And just as with `any`, if the parameters and return type aren't valid for the stored object, you get an exception.

janezz55 .

unread,
Mar 3, 2017, 1:24:06 AM3/3/17
to std-pr...@isocpp.org
It could be done like that, but returning a std:any makes the class more user friendly, if the result is discarded, for example. There also won't be any need to specify a return type. Exceptions can be thrown later if the returned any is cast to an invalid type.

Nicol Bolas

unread,
Mar 3, 2017, 2:16:23 AM3/3/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Friday, March 3, 2017 at 1:24:06 AM UTC-5, janezz55 . wrote:
It could be done like that, but returning a std:any makes the class more user friendly, if the result is discarded, for example. There also won't be any need to specify a return type. Exceptions can be thrown later if the returned any is cast to an invalid type.

This is a very confused view of `any`.

`any_cast` doesn't convert things to a type like the given one. It converts to exactly and only one type: the exact type it was given. If you give it a class D, and you `any_cast` it to a B which is a base class, you get an exception. If you cast it to a class that's implicitly convertible from `D`, you get an exception. The only legal thing you can do is `any_cast<D>`.

Under this logic, a function call operator should behave the same way. When making an `any_call`, the user should be required to provide the exact signature of the function. No implicit conversions, no derived-to-base, nada: you call it exactly as it is, and if the signature doesn't match, you get an exception.

This is yet another reason to make it a different type. Because you probably want `any_function`'s call behavior to allow implicit conversions. But `any` doesn't allow implicit conversions. So you want different semantics, and therefore a different type.

janezz55 .

unread,
Mar 3, 2017, 2:54:31 AM3/3/17
to Nicol Bolas, ISO C++ Standard - Future Proposals
I didn't dispute this behavior of std::any in any way. The std::any I propose would know the return type, as it would deduce it at compile time. The user, on the other hand, might not know or even care. The implementation should not force him to know or care.

Giovanni Piero Deretta

unread,
Mar 3, 2017, 5:09:35 AM3/3/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Thursday, March 2, 2017 at 6:26:01 PM UTC, jane...@gmail.com wrote:
I believe that std::any should be made invokable, if an invokable object is stored into it, such as a function pointer, method pointer, or a functor (such as std::function<> and others). This would raise the level of abstraction C++ offers to one comparable to scripting languages, where you can often invoke an arbitrary variable. I've prepared 2 examples:

Any is a polymorphic wrapper for any object modeling the CopyConstructible concept. Anything beyond that is out of scope. In fact any doesn't even provide equality or ordering, which would seem very basic.

What you want is std::function (another polymorphic wrapper for types modeling the FunctionObject concept) . If you want fully dynamic behavior (including runtime type checking of parameters), use function<any(std::vector<any>)> and wrap the stored function in an adaptor that does the unboxing of the parameters.

janezz55 .

unread,
Mar 3, 2017, 5:15:14 AM3/3/17
to ISO C++ Standard - Future Proposals
I already wrote what I needed :) function<any(std::vector<any>)> is simply blasphemous.

Michał Dominiak

unread,
Mar 3, 2017, 5:49:01 AM3/3/17
to ISO C++ Standard - Future Proposals
Please refrain from comments that are not technologically sound and at the same make you sound like a fanatic.

If you want full duck typing on your type system, then please consider using a language that is not C++. And `function<any (vector<any>)>` is exactly what you're asking for, so I don't know why you're so angry at it.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 5:55:17 AM3/3/17
to ISO C++ Standard - Future Proposals
Again, I am not asking for anything. I even wrote an example illustrating what I had in mind.

2017-03-03 11:48 GMT+01:00 Michał Dominiak <gri...@griwes.info>:
Please refrain from comments that are not technologically sound and at the same make you sound like a fanatic.

If you want full duck typing on your type system, then please consider using a language that is not C++. And `function<any (vector<any>)>` is exactly what you're asking for, so I don't know why you're so angry at it.

On Fri, Mar 3, 2017 at 11:15 AM janezz55 . <jane...@gmail.com> wrote:
I already wrote what I needed :) function<any(std::vector<any>)> is simply blasphemous.

2017-03-03 11:09 GMT+01:00 Giovanni Piero Deretta <gpde...@gmail.com>:
On Thursday, March 2, 2017 at 6:26:01 PM UTC, jane...@gmail.com wrote:
I believe that std::any should be made invokable, if an invokable object is stored into it, such as a function pointer, method pointer, or a functor (such as std::function<> and others). This would raise the level of abstraction C++ offers to one comparable to scripting languages, where you can often invoke an arbitrary variable. I've prepared 2 examples:

Any is a polymorphic wrapper for any object modeling the CopyConstructible concept. Anything beyond that is out of scope. In fact any doesn't even provide equality or ordering, which would seem very basic.

What you want is std::function (another polymorphic wrapper for types modeling the FunctionObject concept) . If you want fully dynamic behavior (including runtime type checking of parameters), use function<any(std::vector<any>)> and wrap the stored function in an adaptor that does the unboxing of the parameters.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 6:10:31 AM3/3/17
to ISO C++ Standard - Future Proposals
Let's say you store a lambda object into std::any

std::any a = [](){};

How are you going to obtain the lambda object back? AFAIK it's locked inside the any instance. If std::any had a mechanism of invoking the stored object you could still "reach" it.

Michał Dominiak

unread,
Mar 3, 2017, 6:13:02 AM3/3/17
to ISO C++ Standard - Future Proposals
Show us the actual (i.e. complete) example of why that be useful (and why you wouldn't just use `std::function<void ()>`, or the somewhat proposed function_ref, for that).

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 6:24:43 AM3/3/17
to ISO C++ Standard - Future Proposals
it's just an example of std::any swallowing an object and not giving it back, it's a deficiency.

2017-03-03 12:12 GMT+01:00 Michał Dominiak <gri...@griwes.info>:
Show us the actual (i.e. complete) example of why that be useful (and why you wouldn't just use `std::function<void ()>`, or the somewhat proposed function_ref, for that).

On Fri, Mar 3, 2017 at 12:10 PM janezz55 . <jane...@gmail.com> wrote:
Let's say you store a lambda object into std::any

std::any a = [](){};

How are you going to obtain the lambda object back? AFAIK it's locked inside the any instance. If std::any had a mechanism of invoking the stored object you could still "reach" it.

2017-03-03 11:15 GMT+01:00 janezz55 . <jane...@gmail.com>:
I already wrote what I needed :) function<any(std::vector<any>)> is simply blasphemous.

2017-03-03 11:09 GMT+01:00 Giovanni Piero Deretta <gpde...@gmail.com>:
On Thursday, March 2, 2017 at 6:26:01 PM UTC, jane...@gmail.com wrote:
I believe that std::any should be made invokable, if an invokable object is stored into it, such as a function pointer, method pointer, or a functor (such as std::function<> and others). This would raise the level of abstraction C++ offers to one comparable to scripting languages, where you can often invoke an arbitrary variable. I've prepared 2 examples:

Any is a polymorphic wrapper for any object modeling the CopyConstructible concept. Anything beyond that is out of scope. In fact any doesn't even provide equality or ordering, which would seem very basic.

What you want is std::function (another polymorphic wrapper for types modeling the FunctionObject concept) . If you want fully dynamic behavior (including runtime type checking of parameters), use function<any(std::vector<any>)> and wrap the stored function in an adaptor that does the unboxing of the parameters.


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Giovanni Piero Deretta

unread,
Mar 3, 2017, 6:44:04 AM3/3/17
to ISO C++ Standard - Future Proposals
On Friday, March 3, 2017 at 11:13:02 AM UTC, Michał Dominiak wrote:
Show us the actual (i.e. complete) example of why that be useful (and why you wouldn't just use `std::function<void ()>`, or the somewhat proposed function_ref, for that).

On Fri, Mar 3, 2017 at 12:10 PM janezz55 . <jane...@gmail.com> wrote:
Let's say you store a lambda object into std::any

std::any a = [](){};

How are you going to obtain the lambda object back? AFAIK it's locked inside the any instance. If std::any had a mechanism of invoking the stored object you could still "reach" it.

any_cast. You have to keep the lambda type around of course. If you don't want to, wrap the lambda in a std::function first before putting it in an std::any.
 

janezz55 .

unread,
Mar 3, 2017, 6:47:23 AM3/3/17
to ISO C++ Standard - Future Proposals
What you describe are workarounds. If you want to use a temporary lambda, you won't be able to keep the type around. Maybe you don't want to specify the function signature and so std::function is not appropriate.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 6:59:37 AM3/3/17
to ISO C++ Standard - Future Proposals
As for me being a type ducking proponent... std::any in various forms has been around since 2001, I think. All the while until now you could assign a function pointer or a member function pointer to it as well as copyable function objects. It's nothing new. Adding the invocation feature would simply be a natural development in my opinion.

Michał Dominiak

unread,
Mar 3, 2017, 8:25:53 AM3/3/17
to ISO C++ Standard - Future Proposals
You're proposing a feature for the sake of having a feature. Give us actual use cases if you think that is not true.

Having a feature that no-one will use is not beneficial.

To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 8:31:45 AM3/3/17
to ISO C++ Standard - Future Proposals
We don't need C++, ASM is sufficient, or an arbitrary other computer language. 640k were sufficient at some point in time. I haven't heard a single rational argument from you. I'd hate to have you as a boss.

To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Michał Dominiak

unread,
Mar 3, 2017, 8:46:21 AM3/3/17
to ISO C++ Standard - Future Proposals
You've asked for a feature, and yet you can't produce an example of how that feature would be useful. This is the rational argument: we don't need features that don't have use cases.

Do show us examples of how this is useful and we might reconsider this feature. Plain and simple like that. Throwing logical fallacies around won't change it.

To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 9:05:46 AM3/3/17
to ISO C++ Standard - Future Proposals
When you open your browser the use cases are showing in front of your eyes, JavaScript programs storing functions in a variable. Python, lua and countless other scripts doing the same. I can't believe you haven't seen any of this in practice.



To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Michał Dominiak

unread,
Mar 3, 2017, 9:08:05 AM3/3/17
to ISO C++ Standard - Future Proposals
Show me a problem that you currently have in C++ that this solves.

I don't care about other languages; we're talking about something you want in C++.

To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Edward Catmur

unread,
Mar 3, 2017, 9:22:30 AM3/3/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Friday, 3 March 2017 14:05:46 UTC, janezz55 . wrote:
When you open your browser the use cases are showing in front of your eyes, JavaScript programs storing functions in a variable. Python, lua and countless other scripts doing the same. I can't believe you haven't seen any of this in practice.

It works in scripting languages because they have a rich base type (have you looked at the size of the PyObject vtable?) that erases all the operations the language syntax allows on an object. We don't have that in C++ because of overhead and because it's incompatible with a Turing-complete compile time type system.

Your proposed facility:

* Requires the target type to have exactly 1 call signature, so it won't work with multi-callables, overload combiners, or polymorphic or variadic function objects, esp. closure types.
* Requires the caller to supply exactly the arguments corresponding to the signature of the target type (otherwise UB, assert or throw). So no arithmetic conversions, cvr conversions or implicit conversions. That's a recipe for frustration.
* Asymmetry between argument and return types; why not require the user to specify the return type?
* Overhead: one extra function pointer plus one extra typeid (for the signature type, if extant) per any instance.

Now some constructive suggestions:

* The overhead is a defect of your implementation; you can move those members into the vtable, at the cost of an extra indirection.
* The return type could be provided by having your invoke member function take the return type as the first template parameter, or preferably providing a non-member invoke. That would also allow supplying argument types explicitly:

auto a = any{[](std::string, unsigned) { return true; }};
auto b = invoke<bool, std::string, unsigned>(a, "meow", 1);

Is that useful? I'm not too sure, but at least it's clear what the facility can and cannot do. It still can't accept multi-signature callables.

To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 10:04:04 AM3/3/17
to ISO C++ Standard - Future Proposals
Edward: Thanks for the suggestions. I didn't presume to think my implementation was definitive. It is the closest we can get in C++ to what the scripting languages have, without sacrificing too much, in my opinion. The conversions you mention could be done, but only at the price of significant overhead. Plain std::any does not support conversions when casting either. If I wrote my own any, I'd definitely move everything I could into the vtable of the holder, as you suggest. The any_function implementation is just an example, an idea that occurred to me only gradually.

I don't want the user specify the return type, because this is not traditionally std::any-like. You can store almost anything into a std::any instance, but you don't need to specify anything, there are no template instantiations needed. Only when casting, do you need those.

I like your invoke() idea. If something like that were implemented, I'd be perfectly pleased with it, but really, why not have a operator() as well? It seems prettier to me, scripting language like. We can invoke a variable, just like in a scripting language.

Michal: I'm using this as part of my signal/slot implementation. I don't want to specify function signatures of my slots, that's the only reason why I use this. The slots usually don't have many arguments as you want signal handling to be fast , also conversions cost time so you don't really want them, the single signature problem is not much of a problem. Take a look:

Michał Dominiak

unread,
Mar 3, 2017, 10:10:13 AM3/3/17
to ISO C++ Standard - Future Proposals
So your use-case that's supposed to convince the committee is "I want to throw away type safety for my thing, help me with doing that"?

janezz55 .

unread,
Mar 3, 2017, 10:11:53 AM3/3/17
to ISO C++ Standard - Future Proposals
Michal: You haven't read the code, there is a type_id. Types are checked.

To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Michał Dominiak

unread,
Mar 3, 2017, 10:25:00 AM3/3/17
to ISO C++ Standard - Future Proposals
Sorry; my last message should've read "I want to throw away compile-time type safety [...]".

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 10:27:11 AM3/3/17
to ISO C++ Standard - Future Proposals
Michal: You throw away compile-time type safety every time you use a std::any, this was the case all the way back to 2001.

To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Michał Dominiak

unread,
Mar 3, 2017, 10:31:24 AM3/3/17
to ISO C++ Standard - Future Proposals
Yes; my point is you're asking for an ability to throw away more of it, with an additional cost for everyone who doesn't use this (which is pretty directly against what C++ stands for). I'm pretty confident that this is not the right direction.

Go on, write a paper. We'll see whose opinion the LEWG favors more.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 3, 2017, 10:38:28 AM3/3/17
to ISO C++ Standard - Future Proposals
Additional costs are an additional function pointer (or virtual function, whichever the implementer prefers) and another type_id. As a std::any may contain storage for "small object optimization", this might not be significant.

To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Edward Catmur

unread,
Mar 3, 2017, 11:39:28 AM3/3/17
to std-pr...@isocpp.org
On Fri, Mar 3, 2017 at 3:38 PM, janezz55 . <jane...@gmail.com> wrote:
Additional costs are an additional function pointer (or virtual function, whichever the implementer prefers) and another type_id. As a std::any may contain storage for "small object optimization", this might not be significant.

It's less than that; the invoker and function typeid are the same for any particular contained type, so they can be maintained statically and accessed via the vtable equivalent. For example, in the libstdc++ implementation one would need to add ops _Op_get_function_type_info and _Op_invoke_function. That's zero space increase, zero time increase, only a small code increase, and fully ABI compatible in both directions. Realistically, that should count as zero-cost.
 

janezz55 .

unread,
Mar 3, 2017, 2:22:41 PM3/3/17
to ISO C++ Standard - Future Proposals
True. I guess I need to start writing the paper.

...

Thiago Macieira

unread,
Mar 4, 2017, 12:07:54 AM3/4/17
to std-pr...@isocpp.org
Em sexta-feira, 3 de março de 2017, às 06:05:42 PST, janezz55 . escreveu:
> When you open your browser the use cases are showing in front of your eyes,
> JavaScript programs storing functions in a variable. Python, lua and
> countless other scripts doing the same. I can't believe you haven't seen
> any of this in practice.

I thought we could do that in C++ already:

auto f = [](){};

Of course, C++ is statically typed, so f has a static type. Python, Lua,
JavaScript and countless others aren't.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

Thiago Macieira

unread,
Mar 4, 2017, 12:13:56 AM3/4/17
to std-pr...@isocpp.org
Em sexta-feira, 3 de março de 2017, às 07:03:59 PST, janezz55 . escreveu:
> I like your invoke() idea. If something like that were implemented, I'd be
> perfectly pleased with it, but really, why not have a operator() as well?

How do you pass the template parameters? Look again at the example that you
liked:

auto a = any{[](std::string, unsigned) { return true; }};
auto b = invoke<bool, std::string, unsigned>(a, "meow", 1);

At best, std::any could have a template member invoke, so you'd have:

auto b = a.invoke<bool, std::string, unsigned>("meow", 1);

Is that too different?

Given the Standard Library's API guidelines, it's highly unlikely to get this
as a member, when a generic free function will do.

FrankHB1989

unread,
Mar 13, 2017, 7:50:29 AM3/13/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com


在 2017年3月3日星期五 UTC+8上午5:01:50,Nicol Bolas写道:
On Thursday, March 2, 2017 at 3:15:03 PM UTC-5, janezz55 . wrote:
From my perspective, the user could easily ignore, that std::any is invokable.

Can they? Can you provide an implementation of an invokable `any` which has the exact same overhead as a non-invokable one, so long as you don't actually use the invoking interface?

I'm not saying you're wrong, but as someone who is not an expert on `any` implementations, I have my doubts about this statement.

You can always achieve that by depressing performance of an ordinary `any` implementation to match invokable one. It would not have effect on conformance. Only QoI is concerned:)

I believe that adding a separate class, which would duplicate a lot of what std::any does, would not reflect well on the STL.

It would duplicate some of the the internals of `any`. But being a different type woudl demonstrate a different semantic meaning to code.

True. But `std::any` also does not have stable meaning of "any".
 
Let's rename `any` to `any_object`. Now let's talk about `any_object` in relation to what you want, which is `any_function`.

What does `any_object` represent, semantically? It represents an implicit agreement between the writer of the function taking the `any` and the person providing the value. Both sides must agree on what type(s) that `any_object` will store, and if there is a disagreement or if one side does the wrong thing, exceptions will fly.

It is even not for "any object". As I have argued before, I have expect the word "any" being short for "any first-class object type" (i.e. cv-unqualified non-array object type), but `std::any` has additional refinement of CopyConstructible on the value type, so it is actually for "any copyable cv-unqualified non-array object type" instead. This sounds somewhat arbitrary, similar as "invokable".
 
What does your conceptual `any_function` represent, semantically? It represents, not the type-erasure of a value, but the type-erausre of a function call signature. And therefore, if you see a function that takes a parameter of type `any_function`, you immediately know that this function will call the given object.

And therefore, the agreement between us is different. The agreement is not that I will provide one or more implicitly-defined types that you will eventually `any_cast` to. The agreement is that I will provide objects that can be called with one or more implicitly-defined function call signatures, that you will eventually call.

If they represent different agreements, then they clearly should be different types. Even if 99% of the code implementation between them is identical, they still need to be separate. Because the code that takes an `any_function` does not want to perform `any_cast` on the value it takes. It will perform `any_call` instead. And vice-versa: code that takes `any_object` will not perform `any_call` on it.

I wouldn't mind having this in the `<any>` header. But I don't like the idea of grafting such a substantially different use case into an existing object.

Also, a pedantic note. "STL" does not mean "standard library."

janezz55 .

unread,
Mar 13, 2017, 8:03:58 AM3/13/17
to FrankHB1989, ISO C++ Standard - Future Proposals
> You can always achieve that by depressing performance of an ordinary `any` implementation to match invokable one. It would not have effect on conformance. Only QoI is concerned:)

I don't see how performance would be depressed. The moving/copying part would obviously be the same, you can do:

void f(){}

std::any a(f);

today, and you could do it in 2001. So what remains is to add the invoking part, either as std::invoke or as a member function. This does not affect the performance of the existing std::any implementation in any way.


FrankHB1989

unread,
Mar 13, 2017, 8:18:41 AM3/13/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
The idea of piling new features onto `std::any` further flaws. If `any::operator()` is acceptable, why not `any::operator++`, `any::operator*`, etc? (Then everything is in a mess. And... for different concepts with same signatures but different meanings, they may simply clash.)

Note I do have such things. The fact is I have to reinvent my own version of `any`, because `std::any` exposes too few things can be reused. I want to see if there can be some generic facilities to help users rolling out any `any_*` quickly.

FrankHB1989

unread,
Mar 13, 2017, 8:22:54 AM3/13/17
to ISO C++ Standard - Future Proposals, frank...@gmail.com, jane...@gmail.com


在 2017年3月13日星期一 UTC+8下午8:03:58,janezz55 .写道:
> You can always achieve that by depressing performance of an ordinary `any` implementation to match invokable one. It would not have effect on conformance. Only QoI is concerned:)

I don't see how performance would be depressed. The moving/copying part would obviously be the same, you can do:

void f(){}

std::any a(f);

today, and you could do it in 2001. So what remains is to add the invoking part, either as std::invoke or as a member function. This does not affect the performance of the existing std::any implementation in any way.

Well, that's mostly joking. But seriously, if runtime type safety is not totally thrown away, there would be a few size overhead on binary image, for most typical implementations of the language.

janezz55 .

unread,
Mar 13, 2017, 9:00:59 AM3/13/17
to FrankHB1989, ISO C++ Standard - Future Proposals
Size increase does not imply performance decrease. As far as arithmetic operators are concerned, there's no need to implement them. There is no bottomless sink problem as regards them and std::any. Also their types are not as elaborate as those of the Callables. Compare "int" and "void(*)()", not to mention the lambda types. Delegates are a recurring theme in C++ ever since the 90s. Even now we have a standard signal/slot implementation proposal. An invokable std::any could make implementing callbacks easier for many people.

Jean-Marc Bourguet

unread,
Mar 13, 2017, 9:48:58 AM3/13/17
to ISO C++ Standard - Future Proposals, frank...@gmail.com, jane...@gmail.com
Le lundi 13 mars 2017 14:00:59 UTC+1, janezz55 . a écrit :
Size increase does not imply performance decrease. As far as arithmetic operators are concerned, there's no need to implement them. There is no bottomless sink problem as regards them and std::any. Also their types are not as elaborate as those of the Callables. Compare "int" and "void(*)()", not to mention the lambda types. Delegates are a recurring theme in C++ ever since the 90s. Even now we have a standard signal/slot implementation proposal. An invokable std::any could make implementing callbacks easier for many people.

I feel dense.  Although I understand the interest of a standard signal/slot mechanism, I don't see the use cases of an invokable std::any which would not be adequately served by std::function and lambdas.  Could you expand on them?

Yours,

-- 
Jean-Marc

janezz55 .

unread,
Mar 13, 2017, 10:03:44 AM3/13/17
to Jean-Marc Bourguet, ISO C++ Standard - Future Proposals
consider:

std::map<std::string, std::any> slots;

slots["onClick"] = [](){};

slots["onClick"]();

This would work with my proposed augmentation and it is possible with my example implementation. Most people don't need much beyond that and it is very concise.

Ville Voutilainen

unread,
Mar 13, 2017, 10:13:24 AM3/13/17
to ISO C++ Standard - Future Proposals, Jean-Marc Bourguet
On 13 March 2017 at 16:03, janezz55 . <jane...@gmail.com> wrote:
> consider:
>
> std::map<std::string, std::any> slots;
>
> slots["onClick"] = [](){};
>
> slots["onClick"]();
>
> This would work with my proposed augmentation and it is possible with my
> example implementation. Most people don't need much beyond that and it is
> very concise.

And you don't write that as
std::map<std::string, std::function<void()>> slots;
exactly because...?

janezz55 .

unread,
Mar 13, 2017, 10:18:37 AM3/13/17
to ISO C++ Standard - Future Proposals, ville.vo...@gmail.com
because the number and type of arguments is fixed that way, while std::any can handle any number of arguments of any type, that's why it's called std::any. Say:

slots["selected"] = [](int){};
slots["selected"](1);

would also work.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Thiago Macieira

unread,
Mar 13, 2017, 11:22:17 AM3/13/17
to std-pr...@isocpp.org
On segunda-feira, 13 de março de 2017 07:18:33 PDT janezz55 . wrote:
> because the number and type of arguments is fixed that way, while std::any
> can handle any number of arguments of any type, that's why it's called
> std::any. Say:
>
> slots["selected"] = [](int){};
> slots["selected"](1);
>
> would also work.

That means you must know the exact type from some OOB information. Why can't
you then convert it to std::function back and forth?

slots["selected"] = std::function<void(int)>{[](int) {});

any_cast<std::function<void(int)>>(slots["selected"])(1);

janezz55 .

unread,
Mar 13, 2017, 11:38:28 AM3/13/17
to ISO C++ Standard - Future Proposals
because of information hiding and convenience. Also, why use 2 type erasers? That's inefficient.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Thiago Macieira

unread,
Mar 13, 2017, 11:54:18 AM3/13/17
to std-pr...@isocpp.org
On segunda-feira, 13 de março de 2017 08:38:24 PDT janezz55 . wrote:
> because of information hiding and convenience. Also, why use 2 type
> erasers? That's inefficient.

Because something must know the actual type. Let me take your example:

slots["selected"] = [](int){};
slots["selected"](1);

What happens if I called slos["selected"]()? How about slots["selected"](1.0)?
What should happen here?

a) UB
b) runtime error / exception thrown
c) compile error

Richard Smith

unread,
Mar 13, 2017, 1:50:19 PM3/13/17
to std-pr...@isocpp.org, Ville Voutilainen
On 13 March 2017 at 04:18, janezz55 . <jane...@gmail.com> wrote:
because the number and type of arguments is fixed that way, while std::any can handle any number of arguments of any type, that's why it's called std::any. Say:

slots["selected"] = [](int){};
slots["selected"](1);

would also work.

What about

slots["what_is_my_arity"] = [](auto...){};

? If that's supposed to work, how? (Even if you had a separate any_function type for this idea, it still seems fundamentally unable to handle function templates or overload sets, and it gives you an object with a non-type-safe operator().)

Fundamentally I completely agree with other commenters: operator() is *not* special. This is just a special case of a general desire: to lift a concept into a concrete type that type-erases the implementation of the concept. That sure is a useful idea, but this is not the right way to get there.

2017-03-13 15:13 GMT+01:00 Ville Voutilainen <ville.vo...@gmail.com>:
On 13 March 2017 at 16:03, janezz55 . <jane...@gmail.com> wrote:
> consider:
>
> std::map<std::string, std::any> slots;
>
> slots["onClick"] = [](){};
>
> slots["onClick"]();
>
> This would work with my proposed augmentation and it is possible with my
> example implementation. Most people don't need much beyond that and it is
> very concise.

And you don't write that as
std::map<std::string, std::function<void()>> slots;
exactly because...?

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUZGaH%2BKRrRtA-sdNqYVyo64%2B6OhCSay5JsLTCyYiHS9gQ%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Mar 13, 2017, 2:25:54 PM3/13/17
to ISO C++ Standard - Future Proposals, ville.vo...@gmail.com
On Monday, March 13, 2017 at 1:50:19 PM UTC-4, Richard Smith wrote:
On 13 March 2017 at 04:18, janezz55 . <jane...@gmail.com> wrote:
because the number and type of arguments is fixed that way, while std::any can handle any number of arguments of any type, that's why it's called std::any. Say:

slots["selected"] = [](int){};
slots["selected"](1);

would also work.

What about

slots["what_is_my_arity"] = [](auto...){};

? If that's supposed to work, how? (Even if you had a separate any_function type for this idea, it still seems fundamentally unable to handle function templates or overload sets, and it gives you an object with a non-type-safe operator().)

Fundamentally I completely agree with other commenters: operator() is *not* special. This is just a special case of a general desire: to lift a concept into a concrete type that type-erases the implementation of the concept. That sure is a useful idea, but this is not the right way to get there.

Now that's an interesting idea: `any_concept<ConceptName>`, which would synthesize the operations specified by the concept. Of course, that would require two things we don't have: the ability to introspect the elements of a concept, and the ability to pass concepts to templates.

This is a pretty good argument for making a concept something other than just a function/variable, since this would permit us to provide them as template arguments.

Granted, even those two things wouldn't be enough, since we cannot automatically synthesize arbitrary global interfaces.

Edward Catmur

unread,
Mar 13, 2017, 4:49:01 PM3/13/17
to std-pr...@isocpp.org


On 13 Mar 2017 15:54, "Thiago Macieira" <thi...@macieira.org> wrote:
On segunda-feira, 13 de março de 2017 08:38:24 PDT janezz55 . wrote:
> because of information hiding and convenience. Also, why use 2 type
> erasers? That's inefficient.

Because something must know the actual type. Let me take your example:

slots["selected"] = [](int){};
slots["selected"](1);

What happens if I called slos["selected"]()? How about slots["selected"](1.0)?
What should happen here?

 a) UB
 b) runtime error / exception thrown
 c) compile error

b) in both cases. As discussed above, this is trivial to implement and incurs zero run time cost. 



--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Klaim - Joël Lamotte

unread,
Mar 13, 2017, 4:52:30 PM3/13/17
to std-pr...@isocpp.org, Ville Voutilainen
You are basically describing "virtual concepts" as per this work-in-progress proposal (which decided to go
the languae-feature way for argumented reasons: https://github.com/andyprowl/virtual-concepts
 

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Edward Catmur

unread,
Mar 13, 2017, 5:09:01 PM3/13/17
to std-pr...@isocpp.org


On 13 Mar 2017 20:52, "Klaim - Joël Lamotte" <mjk...@gmail.com> wrote:


On 13 March 2017 at 19:25, Nicol Bolas <jmck...@gmail.com> wrote:
On Monday, March 13, 2017 at 1:50:19 PM UTC-4, Richard Smith wrote:
On 13 March 2017 at 04:18, janezz55 . <jane...@gmail.com> wrote:
because the number and type of arguments is fixed that way, while std::any can handle any number of arguments of any type, that's why it's called std::any. Say:

slots["selected"] = [](int){};
slots["selected"](1);

would also work.

What about

slots["what_is_my_arity"] = [](auto...){};

? If that's supposed to work, how? (Even if you had a separate any_function type for this idea, it still seems fundamentally unable to handle function templates or overload sets, and it gives you an object with a non-type-safe operator().)

Yes, that wouldn't work, except possibly by a tag constructor to select one preferred signature. The operator() is still type safe, it just will never succeed. 


Fundamentally I completely agree with other commenters: operator() is *not* special. This is just a special case of a general desire: to lift a concept into a concrete type that type-erases the implementation of the concept. That sure is a useful idea, but this is not the right way to get there.

See below. I don't think this is correct; Callable is not an expressible concept (as opposed to Callable<Sig>) to my knowledge. 


Now that's an interesting idea: `any_concept<ConceptName>`, which would synthesize the operations specified by the concept. Of course, that would require two things we don't have: the ability to introspect the elements of a concept, and the ability to pass concepts to templates.

This is a pretty good argument for making a concept something other than just a function/variable, since this would permit us to provide them as template arguments.

Granted, even those two things wouldn't be enough, since we cannot automatically synthesize arbitrary global interfaces.


You are basically describing "virtual concepts" as per this work-in-progress proposal (which decided to go
the languae-feature way for argumented reasons: https://github.com/andyprowl/virtual-concepts
 

I may be missing something, but I don't see the immediate relevance to this discussion. As far as I'm aware it is not possible for a concept to model the - ah, concept - of being callable in general, rather than with a particular signature. 

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Matt Calabrese

unread,
Mar 13, 2017, 5:12:16 PM3/13/17
to ISO C++ Standard - Future Proposals, Ville Voutilainen
On Mon, Mar 13, 2017 at 4:52 PM, Klaim - Joël Lamotte <mjk...@gmail.com> wrote:


On 13 March 2017 at 19:25, Nicol Bolas <jmck...@gmail.com> wrote:
On Monday, March 13, 2017 at 1:50:19 PM UTC-4, Richard Smith wrote:
On 13 March 2017 at 04:18, janezz55 . <jane...@gmail.com> wrote:
because the number and type of arguments is fixed that way, while std::any can handle any number of arguments of any type, that's why it's called std::any. Say:

slots["selected"] = [](int){};
slots["selected"](1);

would also work.

What about

slots["what_is_my_arity"] = [](auto...){};

? If that's supposed to work, how? (Even if you had a separate any_function type for this idea, it still seems fundamentally unable to handle function templates or overload sets, and it gives you an object with a non-type-safe operator().)

Fundamentally I completely agree with other commenters: operator() is *not* special. This is just a special case of a general desire: to lift a concept into a concrete type that type-erases the implementation of the concept. That sure is a useful idea, but this is not the right way to get there.

Now that's an interesting idea: `any_concept<ConceptName>`, which would synthesize the operations specified by the concept. Of course, that would require two things we don't have: the ability to introspect the elements of a concept, and the ability to pass concepts to templates.

This is a pretty good argument for making a concept something other than just a function/variable, since this would permit us to provide them as template arguments.

Granted, even those two things wouldn't be enough, since we cannot automatically synthesize arbitrary global interfaces.


You are basically describing "virtual concepts" as per this work-in-progress proposal (which decided to go
the languae-feature way for argumented reasons: https://github.com/andyprowl/virtual-concepts

Dynamic/virtual concepts (type-erasure based on concepts) is basically what the Swift language does and it is powerful. All that a std::function is is the dynamic version of the Invocable (previously "Callable") concept. I see this being achievable at the language level with C++0x concepts, but I am very skeptical about it being possible with Concepts TS due to the nature of the constraints.

Thiago Macieira

unread,
Mar 13, 2017, 7:15:30 PM3/13/17
to std-pr...@isocpp.org
Em segunda-feira, 13 de março de 2017, às 13:48:59 PDT, 'Edward Catmur' via
ISO C++ Standard - Future Proposals escreveu:
> On 13 Mar 2017 15:54, "Thiago Macieira" <thi...@macieira.org> wrote:
>
> On segunda-feira, 13 de março de 2017 08:38:24 PDT janezz55 . wrote:
> > because of information hiding and convenience. Also, why use 2 type
> > erasers? That's inefficient.
>
> Because something must know the actual type. Let me take your example:
>
> slots["selected"] = [](int){};
> slots["selected"](1);
>
> What happens if I called slos["selected"]()? How about
> slots["selected"](1.0)?
> What should happen here?
>
> a) UB
> b) runtime error / exception thrown
> c) compile error
>
>
> b) in both cases. As discussed above, this is trivial to implement and
> incurs zero run time cost.

Except for the part that it's not trivial and has a runtime cost.

Arthur O'Dwyer

unread,
Mar 13, 2017, 7:15:31 PM3/13/17
to ISO C++ Standard - Future Proposals
On Monday, March 13, 2017 at 8:54:18 AM UTC-7, Thiago Macieira wrote:
On segunda-feira, 13 de março de 2017 08:38:24 PDT janezz55 . wrote:
> because of information hiding and convenience. Also, why use 2 type
> erasers? That's inefficient.

Because something must know the actual type. Let me take your example:

slots["selected"] = [](int){};
slots["selected"](1);

What happens if I called slos["selected"]()? How about slots["selected"](1.0)?
What should happen here?

 a) UB
 b) runtime error / exception thrown
 c) compile error

This relates to a feature that I wish existed, but which is not actually implementable: std::visit for std::any objects!

    std::any x = something();
    my::visit(x, [](auto&& arg) {
        printf("The dynamic type of x is %s\n", typeid(arg).name());
    });

If this were possible to implement, then it would solve the OP's problem (just define your visitor as [](auto&& arg){ arg(); }); but my strong impression is that it's impossible to implement this my::visit() function, because heck, the compiler has to generate code at some point, and how can it possibly generate "all possible instantiations of that lambda's templated operator()" when the set of possible types is open-ended?
That's why we got std::visit for std::variant, but not for std::any — because it is technologically impossible to implement std::visit for std::any.

The same impossibility objection applies for any open-ended visitation idiom, no matter whether you spell it my::visit(std::any, F&&) or std::any::operator()(A&&...).

If my argument above is wrong, please let me know and I'll write the obvious proposal for Albuquerque. ;)

–Arthur

Nicol Bolas

unread,
Mar 13, 2017, 7:33:41 PM3/13/17
to ISO C++ Standard - Future Proposals
Hm... That's a really good point.

`std::function` works because it is statically provided the call signature to use. Therefore, when it does its type erasure magic, it has a base class with a virtual function that has the call signature. That is, as I understand it, the basic essence of how it does type erasure. This base class is defined/referenced as part of `function`'s implementation.

So how would such type erasure work when the signature is not part of the erasing type's definition? `any` works because its type erasure only needs to support one operation: fetching the `type_info` for the original type.

Also, it's important to remember that you cannot declare a template function to be virtual. So you can't get around this by declaring the `operator()` to be a variadic template.

Nevin Liber

unread,
Mar 13, 2017, 8:36:13 PM3/13/17
to std-pr...@isocpp.org
On Mon, Mar 13, 2017 at 6:33 PM, Nicol Bolas <jmck...@gmail.com> wrote:
So how would such type erasure work when the signature is not part of the erasing type's definition? `any` works because its type erasure only needs to support one operation: fetching the `type_info` for the original type.

Copying and destruction are also operations on any that are type erased.
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com>  +1-847-691-1404

Tony V E

unread,
Mar 13, 2017, 8:38:57 PM3/13/17
to Standard Proposals

janezz55 .

unread,
Mar 14, 2017, 12:15:42 AM3/14/17
to ISO C++ Standard - Future Proposals
I think boosts class is a costumizable type eraser. you can generate your own std::function with it. Std::any is simple to use and relieves the user of having to specify a signature, hides the complexity from the user. As far as a visitor is concerned, I think it should be possible to obtain a type id and then you'd have to any cast. But I never needed that. why a visitor, if you have type id already?

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Edward Catmur

unread,
Mar 14, 2017, 4:17:24 AM3/14/17
to std-pr...@isocpp.org
On Mon, Mar 13, 2017 at 11:15 PM, Thiago Macieira <thi...@macieira.org> wrote:
Em segunda-feira, 13 de março de 2017, às 13:48:59 PDT, 'Edward Catmur' via
ISO C++ Standard - Future Proposals escreveu:
> On 13 Mar 2017 15:54, "Thiago Macieira" <thi...@macieira.org> wrote:
>
> On segunda-feira, 13 de março de 2017 08:38:24 PDT janezz55 . wrote:
> > because of information hiding and convenience. Also, why use 2 type
> > erasers? That's inefficient.
>
> Because something must know the actual type. Let me take your example:
>
> slots["selected"] = [](int){};
> slots["selected"](1);
>
> What happens if I called slos["selected"]()? How about
> slots["selected"](1.0)?
> What should happen here?
>
>  a) UB
>  b) runtime error / exception thrown
>  c) compile error
>
>
> b) in both cases. As discussed above, this is trivial to implement and
> incurs zero run time cost.

Except for the part that it's not trivial and has a runtime cost.

A small code size increase, admittedly, but zero extra code executed if the feature is not used. As for triviality, that's in the eye of the beholder, but I'm certain that any library maintainer presented with the specification would consider the implementation trivial.
 
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 14, 2017, 4:23:51 AM3/14/17
to ISO C++ Standard - Future Proposals
My thoughts exactly. I'm amazed how complex signal/slot implementations of many C++ applications are, I think my proposal would simplify these. The small size increase is better than introducing a new language feature (C# delegate comes to mind).

Edward Catmur

unread,
Mar 14, 2017, 4:30:35 AM3/14/17
to std-pr...@isocpp.org
That's the implementation technique used in toy examples and student exercises. Production implementations use more efficient and more evolvable techniques, although the expressive power is the same.

So how would such type erasure work when the signature is not part of the erasing type's definition? `any` works because its type erasure only needs to support one operation: fetching the `type_info` for the original type.

See above. The signature is supplied at construction time and at calling time (possibly implicitly both times), so it does not need to be erased. (It needs to be stored, so that it can be checked at calling time.) All that is erased is the nested-name-specifier part of the call operator, T in R (T::)(A...) to R(A...).

Also, it's important to remember that you cannot declare a template function to be virtual. So you can't get around this by declaring the `operator()` to be a variadic template.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Mar 14, 2017, 9:27:49 AM3/14/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Tuesday, March 14, 2017 at 4:23:51 AM UTC-4, janezz55 . wrote:
My thoughts exactly. I'm amazed how complex signal/slot implementations of many C++ applications are, I think my proposal would simplify these.

How is providing a specific function call signature a significant part of the complexity of signal implementations in C++? Equally importantly, exactly how does it make sense for two signal receiving functions in the same slot to have different call signatures? Because that's the only difference that your `any` makes: it erases the type of the call signature. If you don't erase that, then you can use `std::function` or similar tools.

To me, the main complexity of C++ signal/slot implementations comes from the fact that C++ has no effective way to remove registered signal handlers without using some sort of handle interface. This is due to the fact that most functors are not equality comparable, and indeed equality comparability doesn't make sense for C++ functors.

The small size increase is better than introducing a new language feature (C# delegate comes to mind).

C# delegates are little more than an object that stores an array of `std::function`s. The call signature is not variable; for any particular delegate, you may only use one particular call signature.

Your `any` changes are overkill for matching C# delegates.

janezz55 .

unread,
Mar 14, 2017, 9:42:47 AM3/14/17
to Nicol Bolas, ISO C++ Standard - Future Proposals
How is providing a specific function call signature a significant part of the complexity of signal implementations in C++? Equally importantly, exactly how does it make sense for two signal receiving functions in the same slot to have different call signatures? Because that's the only difference that your `any` makes: it erases the type of the call signature. If you don't erase that, then you can use `std::function` or similar tools.

You need to provide one signal type for each signal, which means more code, which means greater complexity. They are not allowed to, an exception, assert ... will be raised. Also, look at Qts MOC preprocessor, a very complex code generator. The any changes I propose don't erase the call signature, they simply obtain it automatically, to save the users time. Usually you don't want type conversions in a signal handler, as they cost time.

To me, the main complexity of C++ signal/slot implementations comes from the fact that C++ has no effective way to remove registered signal handlers without using some sort of handle interface. This is due to the fact that most functors are not equality comparable, and indeed equality comparability doesn't make sense for C++ functors.

That's not really relevant here, but my solution to this problem would be to return a lambda as a callback to remove the signal handler after registering it.

Your `any` changes are overkill for matching C# delegates.
I'm not really fluent in C#, but delegate is a language feature. The changes I propose are not significant in any sense.

Nicol Bolas

unread,
Mar 14, 2017, 11:15:48 AM3/14/17
to ISO C++ Standard - Future Proposals, jmck...@gmail.com, jane...@gmail.com
On Tuesday, March 14, 2017 at 9:42:47 AM UTC-4, janezz55 . wrote:
How is providing a specific function call signature a significant part of the complexity of signal implementations in C++? Equally importantly, exactly how does it make sense for two signal receiving functions in the same slot to have different call signatures? Because that's the only difference that your `any` makes: it erases the type of the call signature. If you don't erase that, then you can use `std::function` or similar tools.

You need to provide one signal type for each signal, which means more code, which means greater complexity.

So you see `vector<int>` and `vector<float>` as "more code, which means greater complexity"? Because that's what we're talking about: a different template instantiation.

I cannot agree that this is a significant problem for actual user code.

They are not allowed to, an exception, assert ... will be raised.

... I don't know what you're talking about here.

Also, look at Qts MOC preprocessor, a very complex code generator.

So in exactly what way would these `any` changes reduce Qt's MOC complexity with regard to signals/slots? Also, the reasons Qt gives for using MOC for signals/slots doesn't include "the standard library doesn't have a signature-erased `function` type". If they wanted to use one, they could have written one themselves, rather than relying on code generation.

So even if we accept your premise that signals/slots require lots of complexity in C++, it is not clear at all that this `any` change would solve that problem.

The any changes I propose don't erase the call signature,

If the signature isn't present in the typename of `any`, then the signature has been erased. Much like `any` erases the type of the object it contains.

they simply obtain it automatically, to save the users time.

How exactly does this save the user time?

Usually you don't want type conversions in a signal handler, as they cost time.

To me, the main complexity of C++ signal/slot implementations comes from the fact that C++ has no effective way to remove registered signal handlers without using some sort of handle interface. This is due to the fact that most functors are not equality comparable, and indeed equality comparability doesn't make sense for C++ functors.

That's not really relevant here, but my solution to this problem would be to return a lambda as a callback to remove the signal handler after registering it.

So it's just like any other slot handle, except much harder to work with, since it doesn't have a well-defined type. I fail to see how that is a better approach than using a real slot handle.

Thiago Macieira

unread,
Mar 14, 2017, 12:04:07 PM3/14/17
to std-pr...@isocpp.org
On terça-feira, 14 de março de 2017 01:17:21 PDT 'Edward Catmur' via ISO C++
Standard - Future Proposals wrote:
> Because something must know the actual type. Let me take your example:
> > > slots["selected"] = [](int){};
> > > slots["selected"](1);
> > >
> > > What happens if I called slos["selected"]()? How about
> > > slots["selected"](1.0)?
> > > What should happen here?
> > >
> > > a) UB
> > > b) runtime error / exception thrown
> > > c) compile error
> > >
> > >
> > > b) in both cases. As discussed above, this is trivial to implement and
> > > incurs zero run time cost.
> >
> > Except for the part that it's not trivial and has a runtime cost.
>
> A small code size increase, admittedly, but zero extra code executed if the
> feature is not used. As for triviality, that's in the eye of the beholder,
> but I'm certain that any library maintainer presented with the
> specification would consider the implementation trivial.

If it generates code, then the cost is non-zero, even if not executed (larger
binaries -> higher cache miss rate).

More importantly, it needs to save some kind of erasure for when the callable
would be used, as a void function taking int is not the same type as a lambda
taking int, and neither is the same as a function taking int and returning a
large structure. That means the sizeof(std::any) has increase and that has a
cost for everyone who uses it.

So, no, the cost is most definitely not zero.

As for triviality, see the erasure above.

Thiago Macieira

unread,
Mar 14, 2017, 12:11:17 PM3/14/17
to std-pr...@isocpp.org
On terça-feira, 14 de março de 2017 06:27:49 PDT Nicol Bolas wrote:
> To me, the main complexity of C++ signal/slot implementations comes from
> the fact that C++ has no effective way to remove registered signal handlers
> without using some sort of handle interface. This is due to the fact that
> most functors are not equality comparable, and indeed equality
> comparability doesn't make sense for C++ functors.

The complexity comes from other things too, like thread-safety. What happens
if the connection list of the signal emitted is modified while inspecting that
list?

Another one that comes to mind is how to uniquely identify as signal without
increasing the sender's object size. Using PMFs is not easy in C++.

Finally, note that the type erasure is actually the least of the problems, at
least in Qt's signal/slot implementation. The types are erased at a higher
layer (in user code). The connection lists only need one type:

void (int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)

See https://code.woboq.org/qt5/qtbase/src/corelib/kernel/
qobject_impl.h.html#QtPrivate::QSlotObjectBase.

Edward Catmur

unread,
Mar 14, 2017, 12:42:30 PM3/14/17
to std-pr...@isocpp.org

On 14 Mar 2017 16:04, "Thiago Macieira" <thi...@macieira.org> wrote:
On terça-feira, 14 de março de 2017 01:17:21 PDT 'Edward Catmur' via ISO C++
Standard - Future Proposals wrote:
> Because something must know the actual type. Let me take your example:
> > > slots["selected"] = [](int){};
> > > slots["selected"](1);
> > >
> > > What happens if I called slos["selected"]()? How about
> > > slots["selected"](1.0)?
> > > What should happen here?
> > >
> > > a) UB
> > > b) runtime error / exception thrown
> > > c) compile error
> > >
> > >
> > > b) in both cases. As discussed above, this is trivial to implement and
> > > incurs zero run time cost.
> >
> > Except for the part that it's not trivial and has a runtime cost.
>
> A small code size increase, admittedly, but zero extra code executed if the
> feature is not used. As for triviality, that's in the eye of the beholder,
> but I'm certain that any library maintainer presented with the
> specification would consider the implementation trivial.

If it generates code, then the cost is non-zero, even if not executed (larger
binaries -> higher cache miss rate).

Potentially, yes. In practice it's very difficult to measure. 

More importantly, it needs to save some kind of erasure for when the callable
would be used, as a void function taking int is not the same type as a lambda
taking int, and neither is the same as a function taking int and returning a
large structure. That means the sizeof(std::any) has increase and that has a
cost for everyone who uses it.

So, no, the cost is most definitely not zero.

That can be held behind the vptr, or in practice the op handler. Just add two vtable slots or ops. (libstdc++ and libcxx use ops; I can't remember what MSVC uses. Boost.Any uses for-goodness polymorphism, wow. Still zero runtime memory cost.) 

As for triviality, see the erasure above.

I'd consider that trivial. 

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Thiago Macieira

unread,
Mar 14, 2017, 3:40:18 PM3/14/17
to std-pr...@isocpp.org
On terça-feira, 14 de março de 2017 09:42:27 PDT 'Edward Catmur' via ISO C++
Standard - Future Proposals wrote:
> That can be held behind the vptr, or in practice the op handler. Just add
> two vtable slots or ops. (libstdc++ and libcxx use ops; I can't remember
> what MSVC uses. Boost.Any uses for-goodness polymorphism, wow. Still zero
> runtime memory cost.)
>
> As for triviality, see the erasure above.
>
>
> I'd consider that trivial.

Then patch it and you'll see.

Specifically, how to implement the throw case when the parameters don't match.

And do they need to match exactly, or will promotion/demotion rules apply? How
about type conversions, like the string -> string_view case in the other
thread?

janezz55 .

unread,
Mar 14, 2017, 7:38:55 PM3/14/17
to ISO C++ Standard - Future Proposals
So you see `vector<int>` and `vector<float>` as "more code, which means greater complexity"? Because that's what we're talking about: a different template instantiation.

I didn't have that in mind at all. Currently signal/slots outside of Qt's mechanism are used something like:

signal_t s<void()> clicked;
// ...
// a whole bunch of signal declarations

That can be reduced to a single line, for example:

std::map<std::string, std::any> signals;

they simply obtain it automatically, to save the users time.

They can change the signatures of signal handlers without updating code as much as would be necessary otherwise.

So in exactly what way would these `any` changes reduce Qt's MOC complexity with regard to signals/slots? Also, the reasons Qt gives for using MOC for signals/slots doesn't include "the standard library doesn't have a signature-erased `function` type". If they wanted to use one, they could have written one themselves, rather than relying on code generation.

It would make that code-generating approach unnecessary. See:




--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Mar 14, 2017, 8:32:17 PM3/14/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Tuesday, March 14, 2017 at 7:38:55 PM UTC-4, janezz55 . wrote:
So you see `vector<int>` and `vector<float>` as "more code, which means greater complexity"? Because that's what we're talking about: a different template instantiation.

I didn't have that in mind at all. Currently signal/slots outside of Qt's mechanism are used something like:

signal_t s<void()> clicked;
// ...
// a whole bunch of signal declarations

That can be reduced to a single line, for example:

std::map<std::string, std::any> signals;

they simply obtain it automatically, to save the users time.

I'm going to forget for the moment that `any` has no mechanism to allow multiple users to add multiple callbacks to the same object, while `signal_t` does. So really, what you'd need is a `vector<any>` along with various controlling info and so forth to unregister functions. But again, let's ignore that.

I am mostly ignorant of how Qt's signals/slots stuff works. However, I'm fairly sure that having a single variable declaration doesn't save users any time over multiple declarations. Why? Because they still have to populate that `map`.

The initializer may not be in the header. But it still has to exist. And therefore, it is the difference between:

signal_t s<void()> sig1;
signal_t s
<void(int)> sig2;
signal_t s
<void(float)> sig3;

And:

std::map<std::string, std::any> signals = {
   
{"sig1", {}},
   
{"sig2", {}},
   
{"sig3", {}}};

I fail to see how this saved anyone time. Indeed it now takes up time, since I have to do a map access in order to get to a signal. The other way, it's just a member access, which is comparably negligible. So that's wasting time; specifically, runtime performance. And memory allocation overhead.

Also, with individual declarations, it is impossible for me to accidentally misspell a signal name without the compiler complaining. Whereas the runtime version makes it very possible for me to misspell signal names.

Lastly, considering that Qt's signals/slots are all based on code generation, if Qt wanted to do their signals with type-erased function signatures, they could have. We therefore must assume that they explicitly choose not to.

They can change the signatures of signal handlers without updating code as much as would be necessary otherwise.

Um, how? If you change the signature of a signal, then every handler registered to it must match. And since we're talking `any`, it has to match the exact signature provided (just as `any_cast` requires an exact match of the type).

All you've done is make the necessary matching be implicit rather than explicit.
 
So in exactly what way would these `any` changes reduce Qt's MOC complexity with regard to signals/slots? Also, the reasons Qt gives for using MOC for signals/slots doesn't include "the standard library doesn't have a signature-erased `function` type". If they wanted to use one, they could have written one themselves, rather than relying on code generation.

It would make that code-generating approach unnecessary.

If you read what I linked to, you'll see that they use the code generator for a lot more than signals/slots. So it's not going away, no matter what you do with `any`.


... it'd be nice if you explained what code is on that site that is relevant to this discussion.

Edward Catmur

unread,
Mar 14, 2017, 9:08:16 PM3/14/17
to std-pr...@isocpp.org
On Tue, Mar 14, 2017 at 7:40 PM, Thiago Macieira <thi...@macieira.org> wrote:
On terça-feira, 14 de março de 2017 09:42:27 PDT 'Edward Catmur' via ISO C++
Standard - Future Proposals wrote:
> That can be held behind the vptr, or in practice the op handler. Just add
> two vtable slots or ops. (libstdc++ and libcxx use ops; I can't remember
> what MSVC uses. Boost.Any uses for-goodness polymorphism, wow. Still zero
> runtime memory cost.)
>
> As for triviality, see the erasure above.
>
>
> I'd consider that trivial.

Then patch it and you'll see.

That took a little over an hour, mostly due to unfamiliarity with the libcxx build system (I was initially going to implement it on top of libstdc++ but got bored waiting for the gcc git tree to download).
 
Specifically, how to implement the throw case when the parameters don't match.

Compare typeids of signatures and throw on mismatch.

And do they need to match exactly, or will promotion/demotion rules apply? How
about type conversions, like the string -> string_view case in the other
thread?

Yes, an exact match is required. Arguments can be converted at call time, but the supplied signature must match exactly.

Thiago Macieira

unread,
Mar 14, 2017, 9:44:00 PM3/14/17
to std-pr...@isocpp.org
Em terça-feira, 14 de março de 2017, às 16:38:52 PDT, janezz55 . escreveu:
> I didn't have that in mind at all. Currently signal/slots outside of Qt's
> mechanism are used something like:
>
> signal_t s<void()> clicked;
> // ...
> // a whole bunch of signal declarations
>
> That can be reduced to a single line, for example:
>
> std::map<std::string, std::any> signals;
>
> they simply obtain it automatically, to save the users time.

Now you introduce the possibility of typos, because you have something (a
std::string) that the compiler cannot check. I advise against designing your
API like this.

> They can change the signatures of signal handlers without updating code as
> much as would be necessary otherwise.

And that's probably even worse, because now suddenly a slot that used to work
when connected to a given signal will produce an exception.

In fact, I've said time and again: signals ought to be noexcept (or close to).
A slot shouldn't throw, since the signal emitter shouldn't have to care about
a mistake that happened because a third party connected the signal to the
slot. But this means that you cannot have a conversion problem from std::any
to the correct type, which in turn means that the code that connected must
have a way to ensure that the types are correct.

By type-erasing the signal, you lose that.

> So in exactly what way would these `any` changes reduce Qt's MOC complexity
> with regard to signals/slots? Also, the reasons Qt gives for using MOC
> <http://doc.qt.io/qt-5/why-moc.html> for signals/slots doesn't include "the
> standard library doesn't have a signature-erased `function` type". If they
> wanted to use one, they could have written one themselves, rather than
> relying on code generation.
>
> It would make that code-generating approach unnecessary. See:
>
> https://github.com/user1095108/crl

You forgot all the other reasons. One of them is what I gave above: ensuring
the correct parameter types between the signal and the slot. If you erase the
type in the public API[*], you lose that. Qt's signal-slot mechanism, because
it has an actual type, allows the connect() code to ensure the proper
connection. More than that, it also allows conversion, so you can connect a
signal that carries (int, int) to a slot that takes (unsigned long long).

[*] in the public API; whatever you use in the internals to keep your
connection list is your business. Type erasure here makes sense.

The next reason is the need to be able to add signals to an existing class
without changing the class layout. The only thing that can accomplish that in
the current ABIs are member functions.

And third, we need to be able to interact with RPC mechanisms and other
languages, which is the reason another reason MOC must still exist.

If you put all of those together, then not even when we have C++ Reflection
will MOC go away. It might be simplified, but something must implement those
member functions.

Thiago Macieira

unread,
Mar 14, 2017, 9:58:15 PM3/14/17
to std-pr...@isocpp.org
Em terça-feira, 14 de março de 2017, às 18:08:14 PDT, 'Edward Catmur' via ISO
C++ Standard - Future Proposals escreveu:
> Sure:
> https://github.com/llvm-mirror/libcxx/compare/master...ecatmur:any-invoke
> That took a little over an hour, mostly due to unfamiliarity with the
> libcxx build system (I was initially going to implement it on top of
> libstdc++ but got bored waiting for the gcc git tree to download).

Yeah, that takes a while. You can help by downloading only the master branch.

> > Specifically, how to implement the throw case when the parameters don't
> > match.
>
> Compare typeids of signatures and throw on mismatch.

Please write some tests. I don't think you've covered enough.

Specifically, I think this is a deal breaker:

> > And do they need to match exactly, or will promotion/demotion rules apply?
> > How
> > about type conversions, like the string -> string_view case in the other
> > thread?
>
> Yes, an exact match is required. Arguments can be converted at call time,
> but the supplied signature must match exactly.

Note that it's an *exact* exact type match. That is, a const int& parameter is
not the same as int. To operate this callable, you must ensure that the _A
template type pack matches completely exactly.

That is, these two produce different signatures:

std::string s("Hello");
std::invoke(myany, s);
std::invoke(myany, std::string("Hello"));

Because of that, every time you try to pass a variable instead of a temporary,
you'd have to explicitly make it rvalue.

Therefore, I'd say that requiring exact match is not acceptable and leads to
unusable API. You need to insert some leeway.

Let us know what you come up with.

Thiago Macieira

unread,
Mar 14, 2017, 11:18:58 PM3/14/17
to std-pr...@isocpp.org
Em terça-feira, 14 de março de 2017, às 17:32:17 PDT, Nicol Bolas escreveu:
> I am mostly ignorant of how Qt's signals/slots stuff works. However, I'm
> fairly sure that having a single variable declaration doesn't save users
> any time over multiple declarations. Why? Because they still have to
> populate that `map`.

It doesn't. A single variable would make things worse. See my other reply.

> Lastly, considering that Qt's signals/slots are all based on code
> generation, if Qt *wanted* to do their signals with type-erased function
> signatures, they could have. We therefore must assume that they explicitly
> choose not to.

The public API is not type-erased; the internal implementation erases the
type.

== Simplified, crash course in Qt's signal-slot implementation ==

A signal is a member function, such as:

void channelBytesWritten(int channel, qint64 bytes);

That function is implemented by moc, which simply puts all the parameters in a
type-erased array:

void QIODevice::channelBytesWritten(int _t1, qint64 _t2)
{
void *_a[] = { nullptr,
const_cast<void*>(reinterpret_cast<const void*>(&_t1)),
const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
QMetaObject::activate(this, &staticMetaObject, 3, _a);
}

Internally, QObject has an associative container that (indirectly) associates
1 x void (QObject:: *)() to N x callable(void **)

This allows QObject to keep a single structure that applies to all signals and
can operate without having to care what the actual signals and slot types are.

The magic happens in the connect() call. When you do:

connect(sender, &QIODevice::channelBytesWritten, [](unsigned) { });

the template connect() function will register the actual mapper, which is:

static void call(Function &f, void **arg)
{
f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
}

SignalArgs and II are template parameter packs; SignalArgs is shortened to the
number of arguments in the slot function. This "call" function does the type
conversion and, because it must compile, checks that the arguments are
compatible. That is, if you tried to connect the signal above to [](void *),
the function wouldn't compile as f(*reinterpret_cast<int *>(arg[1])) wouldn't
compile.





It's actually more complicated than I described, because:
a) there's the cross-thread functionality which must copy the signal's values
and post that to another thread (think std::vector<std::any>)
b) PMFs are extremely hard to manipulate, so the internal associative
container maps a signal ID to the callable; the connect() function obtains
that ID at runtime by querying more MOC-generated code (it's that
"3" you see in the MOC-generated code for the signal)
c) I didn't show in the callable the code that deals with non-void return
types. Signals and slots can return and they must match too. The return is
that "nullptr" in the first element of the void** array.
d) the connection list is more complex than a simple associative container,
as each connection belongs to both sender and receiver. When a QObject
is destroyed, it must clear the connections in all senders and receivers
it is connected to.
e) I didn't include the part about managing the callable object's lifetime
and the QMetaObject::Connection handle that QObject::connect returns.
f) there's the legacy, string-based connect code that must keep working

Arthur O'Dwyer

unread,
Mar 14, 2017, 11:44:27 PM3/14/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Thursday, March 2, 2017 at 10:26:01 AM UTC-8, jane...@gmail.com wrote:
I believe that std::any should be made invokable, if an invokable object is stored into it, such as a function pointer, method pointer, or a functor (such as std::function<> and others). This would raise the level of abstraction C++ offers to one comparable to scripting languages, where you can often invoke an arbitrary variable. I've prepared 2 examples:


These examples are built around a std::any lookalike, but their functionality could be easily merged into a std.:any, asserts could be substituted for exception throwing and other changes made to make it more std:: palatable.

Sorry it took me until now to follow these links!
Here are the failing test cases I found by inspection of the code.

  gnr::any_function<> f;
  int i = 42;
  f = [a=&i, b=&i, c=&i, d=&i, e=&i]() { };

fails a static_assert. I think this one can be fixed easily.

  auto g = +[](){ return 42; };
  f = g;

gives a nasty compiler error about dropping a `const` qualifier. I think this one can probably be fixed, although to be honest I don't understand why it should have failed. Might even be a compiler bug.

  gnr::any_function<> f;
  int i = 42;
  f = [](const int& i) { };
  f(i);

fails an assertion at runtime. Unfortunately, I think this one is fundamentally unfixable and explodes the whole idea.

–Arthur

janezz55 .

unread,
Mar 15, 2017, 4:55:18 AM3/15/17
to ISO C++ Standard - Future Proposals
I fail to see how this saved anyone time. Indeed it now takes up time, since I have to do a map access in order to get to a signal. The other way, it's just a member access, which is comparably negligible. So that's wasting time; specifically, runtime performance. And memory allocation overhead.

You neglect the fact you need to connect those plethora of signals to slots somewhere. Also, you may hide the map, or whatever you use, behind a convenient interface.

Lastly, considering that Qt's signals/slots are all based on code generation, if Qt wanted to do their signals with type-erased function signatures, they could have. We therefore must assume that they explicitly choose not to.

We can assume many things. In my opinion, Qt implements signal/slots through code generation to support a broader range of compiler than it otherwise might and because of portability concerns.

Um, how? If you change the signature of a signal, then every handler registered to it must match. And since we're talking `any`, it has to match the exact signature provided (just as `any_cast` requires an exact match of the type).

Not having to update

signal_t<signature> of course, just the signal handlers and signal emits.

... it'd be nice if you explained what code is on that site that is relevant to this discussion.

it's an example of a signal/slot implementation. I for one, don't want to use a Qt-specific code generator for my signals and slots. But, in essence, it is not relevant. We are discussing changes to any, not signals and slots. I just would not need to implement any_function. If the object stored in any could be invoked without an any_cast. This means either an operator() overload or std::invoke support for any.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Thiago Macieira

unread,
Mar 15, 2017, 11:13:35 AM3/15/17
to std-pr...@isocpp.org
Em quarta-feira, 15 de março de 2017, às 01:55:12 PDT, janezz55 . escreveu:
> We can assume many things. In my opinion, Qt implements signal/slots
> through code generation to support a broader range of compiler than it
> otherwise might and because of portability concerns.

Opinions are irrelevant here. The use of MOC has nothing to do with
portability and everything to do with the fact that the C++ language does not
have support for reflection.

Thiago Macieira

unread,
Mar 15, 2017, 11:15:53 AM3/15/17
to std-pr...@isocpp.org
Em terça-feira, 14 de março de 2017, às 20:44:27 PDT, Arthur O'Dwyer escreveu:
> gnr::any_function<> f;
> int i = 42;
> f = [](const int& i) { };
> f(i);
>
> fails an assertion at runtime. Unfortunately, I think this one is
> fundamentally unfixable and explodes the whole idea.

Indeed, that's exactly the same issue I found when replying to Edward Catmur
(see Message-ID: <2663636.SEFX8e3ZWL@tjmaciei-mobl1>). I was thinking that it
was unfixable, but I wasn't prepared to make that claim yet.

janezz55 .

unread,
Mar 15, 2017, 11:23:43 AM3/15/17
to ISO C++ Standard - Future Proposals
I beg to differ, MSVC, for example, has for years had problems catching up to the latest standards. Not to mention the more exotic ones, some still at c++98. My signal/slot implementation, for example, does not compile with MSVC, but does compile with clang and gcc.

However, whether you are right or wrong, does not matter here. We should be discussing std::any/std::invoke, not Qt or my library or any advantages either might have.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 15, 2017, 11:26:08 AM3/15/17
to ISO C++ Standard - Future Proposals
Because both of you don't read my posts very well and Ed obviously does. Hint: std::cref().

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Mar 15, 2017, 11:42:15 AM3/15/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
On Wednesday, March 15, 2017 at 11:23:43 AM UTC-4, janezz55 . wrote:
I beg to differ,

Before you get too far in the differing, I should point out that Thiago Macieria is actually one of the developers of Qt. So I'd take his word on it as far as what a Qt tool is intended to do.

However, whether you are right or wrong, does not matter here. We should be discussing std::any/std::invoke, not Qt or my library or any advantages either might have.

But it does matter.

Thus far, the justification for this feature, type-erasing function signatures, has been decidedly lacking. The closest to a useful motivation you've provided is with signals/slots, through your claims that such things are too complicated when you have to provide a function signature.

If we ignore that example, then it ceases to be a motivation. So we have to ask again: why do we need this feature? What purpose does it serve? What problem does it solve?

Michał Dominiak

unread,
Mar 15, 2017, 11:48:18 AM3/15/17
to ISO C++ Standard - Future Proposals, jane...@gmail.com
We are really running in circles now.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 15, 2017, 12:02:43 PM3/15/17
to ISO C++ Standard - Future Proposals
Yes, I'll write a proposal and we will see. Fortunately the language is rich enough to implement this without requiring new language features, so even if I'm the only user, I'll be happy with their decision.

2017-03-15 16:48 GMT+01:00 Michał Dominiak <gri...@griwes.info>:
We are really running in circles now.

On Wed, Mar 15, 2017 at 4:42 PM Nicol Bolas <jmck...@gmail.com> wrote:
On Wednesday, March 15, 2017 at 11:23:43 AM UTC-4, janezz55 . wrote:
I beg to differ,

Before you get too far in the differing, I should point out that Thiago Macieria is actually one of the developers of Qt. So I'd take his word on it as far as what a Qt tool is intended to do.

However, whether you are right or wrong, does not matter here. We should be discussing std::any/std::invoke, not Qt or my library or any advantages either might have.

But it does matter.

Thus far, the justification for this feature, type-erasing function signatures, has been decidedly lacking. The closest to a useful motivation you've provided is with signals/slots, through your claims that such things are too complicated when you have to provide a function signature.

If we ignore that example, then it ceases to be a motivation. So we have to ask again: why do we need this feature? What purpose does it serve? What problem does it solve?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

Thiago Macieira

unread,
Mar 15, 2017, 12:11:03 PM3/15/17
to std-pr...@isocpp.org
Em quarta-feira, 15 de março de 2017, às 08:26:04 PDT, janezz55 . escreveu:
> Because both of you don't read my posts very well and Ed obviously does.
> Hint: std::cref().

That puts the burden in the caller to remember the callee's signature exactly.
I said that this leads to an API that is too difficult to use, too prone to
errors. As such, I don't think it will be accepted.

I recommend searching for an alternative so that it's less prone to errors.
But I don't think there's a solution.

janezz55 .

unread,
Mar 15, 2017, 12:17:39 PM3/15/17
to ISO C++ Standard - Future Proposals
Before you get too far in the differing, I should point out that Thiago Macieria is actually one of the developers of Qt. So I'd take his word on it as far as what a Qt tool is intended to do.

I know, I submitted a thread-related bug to him once. Anyway, I am a very dissatisfied Qt user. You can do almost anything in Qt, but sometimes you need an extraordinary amount of hacks and workarounds to make it happen. I have a long list of unresolved bugs on their bug tracker. This is what happens if the goals of a library are too ambitious, in my opinion. Also, the library is too big in some cases. I couldn't afford to upload it on my 5 GB VPS, for example (i'd need their development file too, as I can't cross compile at home). For me, the problem my proposition solves is my signal/slot implementation. I could not afford to use Qt and I did not trust other implementations on my VPS. The other problem my proposition solves is the bottomless sink, that std::any is for temporary lambda objects.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

janezz55 .

unread,
Mar 15, 2017, 12:36:40 PM3/15/17
to ISO C++ Standard - Future Proposals
That puts the burden in the caller to remember the callee's signature exactly.

That's one of the burdens of std::any, in general. Maybe this is the reason why Qt does not have an any lookalike, just QVariant. But, obviously, std::any made it into the standard.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Thiago Macieira

unread,
Mar 15, 2017, 3:22:05 PM3/15/17
to std-pr...@isocpp.org
Em quarta-feira, 15 de março de 2017, às 09:36:37 PDT, janezz55 . escreveu:
> That puts the burden in the caller to remember the callee's signature
> exactly.
>
> That's one of the burdens of std::any, in general. Maybe this is the reason
> why Qt does not have an any lookalike, just QVariant. But, obviously,
> std::any made it into the standard.

QVariant does have some vtable for supporting additional operations. You can,
for example, iterate over the elements in a sequential container that was
added to a QVariant without knowing what that container was. You get QVariants
as the elements, which you then extract as you please.

If QVariant were to have an invocation operation, we'd take a list of
QVariants as parameters, then convert that to the actual types requested by
the application.

That is, in fact, exactly what queued signal delivery does, as well as RPC
calls from D-Bus, calls from JS in both QtScript and QtQml. It works
sufficiently well for basic types, but has a lot of limitations for user-
provided types. For example, you can't pass a derived class to a function that
takes the base one.

And this all depends on... you guessed, right, MOC. In specific, the invocation
code that MOC generates:

case 0: _t->readyRead(); break;
case 1: _t->channelReadyRead((*reinterpret_cast< int(*)>(_a[1])));
break;
case 2: _t->bytesWritten((*reinterpret_cast< qint64(*)>(_a[1])));
break;

Without moc, you could probably achieve the same using libffi.

Arthur O'Dwyer

unread,
Mar 15, 2017, 4:23:27 PM3/15/17
to ISO C++ Standard - Future Proposals
On Tue, Mar 14, 2017 at 6:27 AM, Nicol Bolas <jmck...@gmail.com> wrote:
On Tuesday, March 14, 2017 at 4:23:51 AM UTC-4, janezz55 . wrote:
My thoughts exactly. I'm amazed how complex signal/slot implementations of many C++ applications are, I think my proposal would simplify these.
How is providing a specific function call signature a significant part of the complexity of signal implementations in C++? Equally importantly, exactly how does it make sense for two signal receiving functions in the same slot to have different call signatures? Because that's the only difference that your `any` makes: it erases the type of the call signature. If you don't erase that, then you can use `std::function` or similar tools.

In fact, once we boil the puzzle down to its essence ("erase everything about an object except its signature, and then erase its signature too until it's time to invoke the object"), we find it's possible to implement "in user-space" today:

class anyfunc {
    std::any object;
  public:
    template<class Sig, class F>
    void emplace(F&& f) {
        object = std::function<Sig>(std::forward<F>(f));
    }

    template<class Sig, class... Args>
    auto invoke(Args&&... args) const {
        const auto *pf = std::any_cast<const std::function<Sig>*>(&object);
        assert(pf != nullptr); // invokee must know the exact signature
        return (*pf)(std::forward<Args>(args)...);
    }
};

void f1(int&) { puts("in f1"); }
void f2(long) { puts("in f2"); }
int main() {
    anyfunc a1, a2;
    int i = 42;
    a1.emplace<void(int&)>(&f1);
    a2.emplace<void(long)>(&f2);
    a1.invoke<void(int&)>(i);  // calls f1
    a2.invoke<void(long)>(i);  // calls f2
}

–Arthur

Edward Catmur

unread,
Mar 15, 2017, 5:10:18 PM3/15/17
to std-pr...@isocpp.org
No thanks. I appreciate your comments, but I only wrote that code to demonstrate the possibility of near zero runtime cost implementation; I'm not interested in making minor and obscuring improvements for the sake of a slightly safer API. If you want to give it a try I'd think that a combination of decay_t and special casing reference_wrapper will cover the cases you've mentioned so far, but I'm sure there are more conversions you could come up with.


--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/cJD8urBWN7c/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
It is loading more messages.
0 new messages