27

I have this code and this outputs the following:

link to the following example https://godbolt.org/z/z8Pn9GsTv

template <typename T>
struct A1 {
    A1() {
        std::cout << "construction of a1" << std::endl;
    }

    ~A1() {
        std::cout << "destruction of a1" << std::endl;
    }
    ~A1() requires (std::is_same_v<T,int>) {
        std::cout << "it is an int" << std::endl;
    }
};

int main() {
    A1 <int>a;
    
    return 0;
}

output:

construction of a1
destruction of a1

but swapping places of destructors it gives other result:

link to the code https://godbolt.org/z/vxj7dPqaj

template <typename T>
struct A1 {
    A1() {
        std::cout << "construction of a1" << std::endl;
    }

    ~A1() requires (std::is_same_v<T,int>) {
        std::cout << "it is an int" << std::endl;
    }
    ~A1() {
        std::cout << "destruction of a1" << std::endl;
    }
};

output:

construction of a1
it is an int

wondering is this a bug?

3 Answers3

14

That's indeed a reported Clang bug1, as noted by Quimby.

Note that the second snippet (the one with the the constrained destructor first) doesn't really "work" in Clang, which just ignores the second destructor2.

Also note that, unlike gcc, at the moment I'm writing, Clang doesn't seem to have implemented [P0848R3] (which is about conditional trivial special member functions) yet3.


1) https://bugs.llvm.org/show_bug.cgi?id=50570
2) See e.g.: https://godbolt.org/z/rff7qfK65
3) See the reported values of the feature test macro __cpp_concepts, e.g. here: https://godbolt.org/z/P4z3Pj5vT

Bob__
  • 12,361
  • 3
  • 28
  • 42
-2

In your 2'nd code,

Try changing this:

A1 <int>a;

To this:

A1 <double>a;

And you'll get the output:

construction of a1
destruction of a1 // With MSVC & GCC compiler

My interpretation here is that when the condition for the first constructor (with requires) fails, the 2'nd constructor is called which prints "destruction of a1" and destroys a.

Here is a more detailed explanation...

The Coding Fox
  • 1,488
  • 1
  • 4
  • 18
-5

On your class template, you have two destructors definition recipe. During instantiation the The compiler gets the "first" recipe that match the signature needed. Depending the compiler depending the result. I think clang, gcc and mingw will provide the same result, msvc approach is different. Better pattern for partial specialization disambiguation precedence chain?

abdeldiaz
  • 11
  • 1
  • 4
  • 2
    "_The compiler gets the "first" recipe that match the signature needed. Depending the compiler depending the result._": No, that's not how it works. The order of declarations is supposed to be irrelevant. I don't know how the linked CWG issue is supposed to relate. – user17732522 May 17 '22 at 15:44
  • "A1 a; generates ~A1() requires (std::is_same_v){...} first and ~A1(){...} after. both are valid. Which one is selected first according to the standard?" – abdeldiaz May 18 '22 at 16:21
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 18 '22 at 16:46
  • @abdeldiaz Normal overload resolution is applied (see https://www.eel.is/c++draft/class.dtor#4) If `std::is_same_v` is satisfied, then the first overload is chosen since it is more constrained than the other (https://www.eel.is/c++draft/over#match.best.general-2.6). If it not satisfied than the other one, since it is the only viable overload. Overload resolution doesn't depend on the order of declarations. If the resolution was ambiguous the program would simply be ill-formed and should fail to compile. – user17732522 May 18 '22 at 17:13