mardi 31 janvier 2023

decltype evaluating the wrong type from an expression list

while experimenting with the answer from This post, ended up with the following piece of code:

#include <iostream>
#include <typeinfo>
 
 namespace Test
 {
    struct MyPtr
    {
        double operator, (int Input)
        {
            std::cout << "Operator, called" << std::endl;
            return 1.0;
        }

        MyPtr operator* ()
        {
            std::cout << "operator* called" << std::endl;
            return *this ;
        }

        MyPtr operator++ ()
        {
            std::cout << "operator++ called" << std::endl;
            return *this;
        }

        MyPtr operator!= (const MyPtr& Other)
        {
            std::cout << "operator!= called" << std::endl;
            return *this;
        }
    };

    struct Foo
    {
        MyPtr Ptr;
    };

    MyPtr begin(Foo& t)
    {
        return t.Ptr;
    }

    MyPtr end(Foo& t)
    {
        return t.Ptr;
    }
 }
 
int main()
{
    std::cout << typeid(decltype(++begin(std::declval<Test::Foo&>()),
                                 *begin(std::declval<Test::Foo&>()), 
                                  std::true_type{})).name() <<std::endl;
}

which yields:

d

Here, d comes from the comma operator. However, as the last expression inside the decltype specifier is std::true_type{}, why does the decltype specifier resolves to the type returned by the comma operator instead of std::true type.

My Theory is that std::true_type can be implicitly cast into an int, which operator,() here takes as a parameter, hence the decltype expression is equivalent to:

    std::cout << typeid(decltype(++begin(std::declval<Test::Foo&>()),
                                 declval<double&>())).name() <<std::endl;

Can you confirm this is correct?

What i am planning on doing when i will have a better grasp of the compiler's behavior, i plan on replacing the contents of the decltype specifier with:

    std::cout << typeid(decltype(void(++begin(std::declval<Test::Foo&>())),
                                 void(*begin(std::declval<Test::Foo&>())), 
                                  std::true_type{})).name() <<std::endl;

which will prevent operator,() from matching, even if it is overridden. Can you also confirm this is correct?

Aucun commentaire:

Enregistrer un commentaire