最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - Why is having ambiguous (default) constructor due to overloading not an error or at least a warning? - Stack Overflow

programmeradmin0浏览0评论

The following class compiles just fine:

class Time {
public:
    Time(int h = 0, int m = 0, int s = 0); // constructor with default parameters 
    Time();                                // default contructor
};

But when trying to use the default constructor one gets the following error:

timeMain.cpp: In function ‘int main()’:
timeMain.cpp:28:9: error: call of overloaded ‘Time()’ is ambiguous
    28 |    Time any;
       |         ^~~

Why is it possible to compile the class definition?

Why is there no error?

Why is there not at least a warning? There is not even anything with -Wall.

I wanted to gather feedback before bringing this up as a feature request for gcc and clang. Maybe I'm missing something.

Thank you!

The following class compiles just fine:

class Time {
public:
    Time(int h = 0, int m = 0, int s = 0); // constructor with default parameters 
    Time();                                // default contructor
};

But when trying to use the default constructor one gets the following error:

timeMain.cpp: In function ‘int main()’:
timeMain.cpp:28:9: error: call of overloaded ‘Time()’ is ambiguous
    28 |    Time any;
       |         ^~~

Why is it possible to compile the class definition?

Why is there no error?

Why is there not at least a warning? There is not even anything with -Wall.

I wanted to gather feedback before bringing this up as a feature request for gcc and clang. Maybe I'm missing something.

Thank you!

Share Improve this question edited Apr 2 at 12:40 nik0x1 1,5482 gold badges8 silver badges26 bronze badges asked Mar 31 at 5:58 joschjosch 7,2304 gold badges45 silver badges54 bronze badges 8
  • 2 I'm not sure Stack Overflow is the best SE site for this. Maybe softwareengineering.stackexchange would have people who are interested in compiler feature questions. – hyde Commented Mar 31 at 6:04
  • Note: only the second constructor is a proper default constructor, and only it will be used when an object is default-constructed. – wohlstad Commented Mar 31 at 6:33
  • Huh? @wohlstad The posted error clearly says otherwise. If what you say were true, would it then not be an error? – j6t Commented Mar 31 at 6:56
  • @j6t my mistake. The 1st one is also a default constructor. This is explicitly mentioned here (... a parameter list where all parameters (except parameter packs)(since C++11) have default arguments). – wohlstad Commented Mar 31 at 7:06
  • 3 Is this really specific to default constructors, or does the same no-error,-no-warning behavior apply in other cases where default arguments result in ambiguous overloads? – ruakh Commented Mar 31 at 7:11
 |  Show 3 more comments

3 Answers 3

Reset to default 4

You appear to be focused on one specific case, a constructor that can be called with zero arguments. However, you can have a similar question about

class DateTime {
public:
    DateTime (Date, int h = 0, int m = 0, int s = 0);
    DateTime (Date);
};

We can make this even more complex with template declarations and concepts. This quickly becomes literally too complex to prove ambiguous. The compiler would need to somehow find a series of arguments A1, A2, ... An for which at least two overloads are ranked the same.

If you want to bring this up as a feature request for gcc/clang, you should explain how the mechanism should work - which signatures T1, T2, ... Tn and U1, U2, ... Un are ambiguous and should produce a warning.

This does not answer the "why" as asked. However I can tell you how you can generate errors for all of the special member functions:

  1. Destructor
  2. Default constructor
  3. Copy constructor
  4. Copy assignment
  5. Move constructor
  6. Move assignment

Every class one authors needs unit testing. And one very simple way to start unit testing for any class it to test that the 6 special member functions behave in the way you intend:

#include <type_traits>
// ...
static_assert( std::is_trivially_destructible_v<Time>);
static_assert(!std::is_default_constructible_v<Time>);
static_assert( std::is_nothrow_copy_constructible_v<Time>);
static_assert( std::is_nothrow_copy_assignable_v<Time>);
static_assert( std::is_nothrow_move_constructible_v<Time>);
static_assert( std::is_nothrow_move_assignable_v<Time>);

As written in the question, this is the set of tests that Time currently passes.

Note that you can test if a type is or is not default constructible (with the preceding !). You can also choose to test if the special member is noexcept or trivial, or decline to test on these characteristics. You have lots of choices.

Having these tests early in a type's development helps as you add data members and base classes to a type.

Having these tests means you can get errors now, with your existing compiler, instead of having to wait for a future language feature that might never arrive.

If desired, you can insert these unit tests right into the header under the class definition so that they get "run" every time the class is compiled. Or, if you would like to save a little compile time, you can put them into a separate unit test source. Your choice.

These tests easily copy/paste/customize to the next class you write.

Why is it possible to compile the class definition?

Because compiler do not check for ambiguous calls during function declaration.

Why is there no error?

Same, compiler considers these two generators to be different.

Why is there not at least a warning? There is not even anything with -Wall.

Default arguments are not taken into account when determining function overloading.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论