explicit blocks

140 views
Skip to first unread message

Michael Boyko

unread,
May 20, 2015, 12:11:23 PM5/20/15
to std-pr...@isocpp.org
An explicit block would be a way to write code where implicit conversions would not be generated. For example:

void fn(double d) {...}

void test()
{
   
int i = 1;
   
double d = 2.0;
   
auto p = make_unique<int>(0);

   
explicit {
      d
= i; //error
      fn
(i); //error
      fn
(d); //fn's body does not inherit explicit
     
bool b = p;
   
}
}

void test2() explicit; //error for declaration

//some shorthand ways to declar explicit for blocks
void test2() explicit //ok for definition
{
   
if (condition) explicit {
   
}
}

Maybe (but not as sure on this one) also for functions as follows:
explicit void fn(double d) //this explicit applies to function params not the body
{
}

void test()
{
   
int i = 1;
   fn
(i); //error
}


Patrice Roy

unread,
May 20, 2015, 12:24:27 PM5/20/15
to std-pr...@isocpp.org
Before going for something like this, there would be a need for some clarifications:

  • would there be an impact on constructors within an explicit block, e.g. making all implicit construction explicit within the block?
  • what would happen if an explicit function calls a non-explicit function? Would the impact be transitive? Would there be an error?
  • can one overload on the explicit-ness of a function?
  • how does it interact with virtual functions?
  • what happens if someone has the funny idea to mark main() as explicit?

That would be a start if we want to weigh in the pros and cons of such a proposal.

Cheers!

--

---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

David Krauss

unread,
May 20, 2015, 12:26:22 PM5/20/15
to std-pr...@isocpp.org
On 2015–05–21, at 12:11 AM, Michael Boyko <mboyk...@gmail.com> wrote:

An explicit block would be a way to write code where implicit conversions would not be generated.

An implicit block would be a way to write code where all explicit conversions would be generated automatically.

For example:

struct foo {
    explicit foo();
};

foo test(void *x) {
    implicit {
        foo *pf = x;
        double *pd = pf;
        short s{ *pd };
        return {}; // per N4074
    }
}

;)

Michael Boyko

unread,
May 20, 2015, 12:32:19 PM5/20/15
to std-pr...@isocpp.org
I tried to hit a couple of these in my examples, but I am shooting from the hip here.


On Wednesday, May 20, 2015 at 11:24:27 AM UTC-5, Patrice Roy wrote:
Before going for something like this, there would be a need for some clarifications:

  • would there be an impact on constructors within an explicit block, e.g. making all implicit construction explicit within the block?
  • what would happen if an explicit function calls a non-explicit function? Would the impact be transitive? Would there be an error?
No. The same function would behave differently depending where it was called from? I'd say no error. thoughts? 
  • can one overload on the explicit-ness of a function?
No. I had an example that made it an error to place it on trailing end of a function declaration but not the definition. Like noexcept. This is why I wasn't so sure about the explicit for the function params (placed before the function).

Klaim - Joël Lamotte

unread,
May 20, 2015, 2:01:48 PM5/20/15
to std-pr...@isocpp.org
I have thought of similar features before, both for explicit conversion and const-ness.
I believe that a scoped or unscoped directive  would be far better because it would make possible to 
force const-ness or explicit-ness to a whole file.
For example, let's say that we are using the "using" directive:

// somefile.cpp

#include <blahblah>

using explict; // Any converting instruction after this point in the current scope
                    // follows explicit casting rules by default.
using const; // Any object defined after this point in the current scope 
                   //is const by default.

void foo(Object& object, double k) // args are not objects defined here, so object is not a const ref
{
    Object w = object.bar(); // w is const
    int u = k; // error
}


I'm assuming here that if these using were in a class, only members of the class would be affected.
If they were in a function definition, only code inside the function body would be affected.

Of course:

 1. it would require a way to specify when to allow implicit casts;
 2. it would require a way to specify that an object is not const - mutable?;
 3. Having a namespace-scoped using directive in a header would be as problematic as currently,
     but I believe that it would trigger obvious enough errors to be detected early and continue 
     to be considered bad practice.

Douglas Boffey

unread,
May 21, 2015, 7:34:05 AM5/21/15
to std-pr...@isocpp.org
Please, keep the explicit qualifier within the body of a function, and
not within the function header—this is a function implementation
restriction, and does not affect the way the function is used (unless
I have totally misunderstood the OP).

Michael Boyko

unread,
May 21, 2015, 8:55:18 AM5/21/15
to std-pr...@isocpp.org


On Thursday, May 21, 2015 at 6:34:05 AM UTC-5, Douglas Boffey wrote:
Please, keep the explicit qualifier within the body of a function, and
not within the function header—this is a function implementation
restriction, and does not affect the way the function is used (unless
I have totally misunderstood the OP).


Correct. My intention is that it is an implementation detail of a function and is not part of the function signature. One would not be able to overload based on if a function is explicit or not. I only pointed out a shorthand way of specifying explicit function blocks (like a function try block). For example:

void fn() explicit {
}


would be identical to:

void fn() {
   
explicit {
   
}
}

 Basically this follows the function try block style:

void fn() try {
} catch (...) {
}


 

Igor Baidiuk

unread,
May 21, 2015, 2:14:12 PM5/21/15
to std-pr...@isocpp.org
Sorry if I missed something, but what problem does this solve? Is this problem so common? Can't it be solved by other means?

Michael Boyko

unread,
May 21, 2015, 4:04:04 PM5/21/15
to std-pr...@isocpp.org


On Thursday, May 21, 2015 at 1:14:12 PM UTC-5, Igor Baidiuk wrote:
Sorry if I missed something, but what problem does this solve? Is this problem so common? Can't it be solved by other means?


I'll point out my personal experience. I've been bit by bugs caused by implicit conversions generally related to overloaded function resolution. I'm sure we all have been bit by a bug caused by narrowing conversions. This would be a tool to control some of these issues.

David Krauss

unread,
May 21, 2015, 10:03:42 PM5/21/15
to std-pr...@isocpp.org
On 2015–05–22, at 4:04 AM, Michael Boyko <mboyk...@gmail.com> wrote:

I'll point out my personal experience. I've been bit by bugs caused by implicit conversions generally related to overloaded function resolution. 

Make user-defined conversions explicit unless implicitness is necessary.

Any necessary implicit conversions would render the explicit block useless. Therefore it would only be useful to perpetuate interfaces that are broken.

I'm sure we all have been bit by a bug caused by narrowing conversions.

Use braces to control narrowing conversions.

long a = x;
int b {a}; // Error

It even works in function arguments:

void f( int );
f({ 5.0 }); // OK
f({ 5.2 }); // Error


If this is unpalatable, at least use -Wnarrowing.

David Krauss

unread,
May 21, 2015, 10:45:34 PM5/21/15
to std-pr...@isocpp.org

On 2015–05–22, at 10:03 AM, David Krauss <pot...@mac.com> wrote:

f({ 5.0 }); // OK

Oops, this is an error. I was thinking of the exemption for exact representation, but that doesn’t apply to floating-integral conversions.

f({ 5L }) would be OK.

Michael Boyko

unread,
May 22, 2015, 10:38:34 AM5/22/15
to std-pr...@isocpp.org, pot...@mac.com
Good advice for sure. But throw in some messy template functions and classes and now you don't even know if the type has a conversion operator or not. Maybe concepts will help in those cases - not sure. Just seem like it would be nice to not generate implicit conversions in some places.
 
Reply all
Reply to author
Forward
0 new messages