Argumenty domyślne w dziwnych miejscach – czyli również od nowicjuszy można się czegoś nauczyć

Jeśli chodzi o C++ to mam o sobie całkiem wysokie mniemanie. Niemniej jednak, nie ma nikogo kto by znał ten język w całości. Ostatnio na forum, w dziale Newbie, zobaczyłem pytanie zawierające kod zbliżony do następującego:

// foo.hpp
struct foo
{
    void bar(int baz);
};
 
// foo.cpp
void foo::bar(int baz = 42)
{
// ...
}

Moją pierwszą odpowiedzią było “to się nie ma prawa skompilować”. Z tym stwierdzeniem był jednak drobny problem: nie było prawdziwe – oba wiodące kompilatory C++, czyli clang i gcc, kompilowały go bez problemów.

Widząc taki stan rzeczy, uznałem, że należy sprawdzić u źródła: obecnego standardu C++. Po pobieżnej lekturze paragrafu N4140 §8.3.6 [dcl.fct.default] Default arguments dowiedziałem się, że to nie tylko “ma prawo” się skompilować, ale również ma obowiązek.

Co ciekawsze cytaty:

N4140 §8.3.6 [dcl.fct.default] Default arguments/4
For non-template functions, default arguments can be added in later declarations of a function in the
same scope. Declarations in different scopes have completely distinct sets of default arguments

Powyższe tyczy się funkcji nie będących elementami klas.

N4140 §8.3.6 [dcl.fct.default] Default arguments/6
the default arguments in a member function definition that appears outside of the class definition are added to the set of default arguments provided by the member function declaration in the class definition

A to tyczy się już konkretnie przykładu, który zrugałem na forum. Jest nawet okraszone (nienormatywnym) komentarzem z przykładem:

class C {
  void f(int i = 3);
  void g(int i, int j = 99);
};
void C::f(int i = 3) {         // error: default argument already
}                              // specified in class scope
void C::g(int i = 88, int j) { // in this translation unit,
}                              // C::g can be called with no argument

Widząc takie coś na code review raczej bym tego nie przepuścił (przynajmniej nie bez bardzo solidnej argumentacji), ale język jako taki wyraźnie na to pozwala.

A problemem na forum nie były dziwnie umieszczone wartości domyślne.

2 thoughts on “Argumenty domyślne w dziwnych miejscach – czyli również od nowicjuszy można się czegoś nauczyć

    1. Generalnie chodzi o to, że takie definicje czynią kod znacznie mniej przenaszalnym, i zmniejszają jego czytelność. Jeśli wywołasz przeniesiesz z foo.cpp do bar.cpp kod wywołujący foo::bar() bez parametrów, to przestanie się on kompilować. W tak trywialnym przykładzie to jest oczywiste, ale jak masz hierarchię klas, przeładowań itd, to przestaje już takie być.

Leave a Reply

Your email address will not be published.