Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nicer syntax for setting default argument value to default constructor

One might want to declare a function with an argument, and specify that the default value for the argument is the result of the type's default constructor:

void foo(a::really::long::type::name arg = a::really::long::type::name()); 

Is there a nicer syntax for this that doesn't involve entering the type name twice? Something like:

void foo(a::really::long::type::name arg = default); 

I realize I can typedef the type name to make it prettier, but I'm curious whether such a syntax exists.

like image 443
TypeIA Avatar asked Jun 30 '16 19:06

TypeIA


People also ask

What is the syntax of default constructor?

A default constructor is a constructor that either has no parameters, or if it has parameters, all the parameters have default values. If no user-defined constructor exists for a class A and one is needed, the compiler implicitly declares a default parameterless constructor A::A() .

What is the default type of argument used in constructor?

The default constructor with argument has a default parameter x, which has been assigned a value of 0.

What is the default value of a constructor?

The default constructor in Java initializes the data members of the class to their default values such as 0 for int, 0.0 for double etc. This constructor is implemented by default by the Java compiler if there is no explicit constructor implemented by the user for the class.


2 Answers

Yes:

void foo(a::really::long::type::name arg = {}); 

To sum up the following standard definitions:

This is list initialization. Depending of the type, aggregate initialization is performed or the object is value initialized, which in turn implies default initialized or zero initialized.

Some "corner" cases are when the type is a specialization of std::initializer_list or when the type has a std::initializer_list constructor (it is called if it has no default constructor)


The relevant standard quotes (in order we encounter definitions):

§8.3.6 Default arguments [dcl.fct.default]

1 If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default argument

5 The default argument has the same semantic constraints as the initializer in a declaration of a variable of the parameter type, using the copy-initialization semantics (8.5)

§8.5.4 List-initialization [dcl.init.list]

1 List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, [...]. An initializer list may be empty. List-initialization can occur in direct-initialization or copy initialization contexts; [..] list-initialization in a copy-initialization context is called copy-list-initialization.

3 List-initialization of an object or reference of type T is defined as follows:

  • If T is an aggregate, aggregate initialization is performed (8.5.1)
  • Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
  • Otherwise, if T is a specialization of std::initializer_list, a prvalue initializer_list object is constructed as described below and used to initialize the object according to the rules for initialization of an object from a class of the same type (8.5).
  • Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7) [...]
  • ...
  • Otherwise, if the initializer list has no elements, the object is value-initialized.

§ 8.5 Initializers [dcl.init]

8 To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;
  • if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;
  • if T is an array type, then each element is value-initialized;
  • otherwise, the object is zero-initialized

7 To default-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor (12.1) for T is called (and the initialization is ill-formed if T has no default constructor or overload resolution (13.3) results in an ambiguity or in a function that is deleted or inaccessible from the context of the initialization);
  • if T is an array type, each element is default-initialized;
  • otherwise, no initialization is performed.

6 To zero-initialize an object or reference of type T means:

  • if T is a scalar type (3.9), the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;
  • if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
  • if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized and padding is initialized to zero bits;
  • if T is an array type, each element is zero-initialized;
  • if T is a reference type, no initialization is performed.

§13.3.1.7 Initialization by list-initialization [over.match.list]

1 When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:

  • Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.
  • If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.

If the initializer list has no elements and T has a default constructor, the first phase is omitted. [...]

like image 67
bolov Avatar answered Oct 08 '22 22:10

bolov


A pedestrian approach is possible, if you control the class of arg. Use a conversion constructor overloaded for an enum:

// Define this enum, and then write constructors which take dfl enum dfl { dflval };  class a_really_long_type_name { public:   a_really_long_type_name(dfl arg = dflval); }; 

Now foo can be:

void foo(a_really_long_type_name arg = dflval); 

If you can apply this, a benefit is portability; this should work fine in a twenty-five-year-old C++ compiler.

Multiple classes can all share this dfl enum and its dflval-flavored zero; it's like having a new keyword.

Because an enum is a distinct type, this doesn't interfere with constructor overloads for integer types or characters and so on.

The downside is working it into some classes which already have default construction provided via argument defaulting, which leads to duplicate constructor code.

like image 38
Kaz Avatar answered Oct 08 '22 22:10

Kaz