экспериментируя с ответом от Этот пост, в итоге получился следующий кусок кода:
#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;
}
который дает:
d
Здесь d происходит от оператора запятой. Однако, поскольку последним выражением в спецификаторе decltype является std::true_type{}, почему спецификатор decltype разрешается в тип, возвращаемый оператором запятой, а не в тип std::true.
Моя теория заключается в том, что std::true_type можно неявно привести к типу int, который оператор () здесь принимает в качестве параметра, поэтому выражение decltype эквивалентно:
std::cout << typeid(decltype(++begin(std::declval<Test::Foo&>()),
declval<double&>())).name() <<std::endl;
Вы можете подтвердить, что это правильно?
Что я планирую делать, когда лучше разберусь в поведении компилятора, я планирую заменить содержимое спецификатора decltype на:
std::cout << typeid(decltype(void(++begin(std::declval<Test::Foo&>())),
void(*begin(std::declval<Test::Foo&>())),
std::true_type{})).name() <<std::endl;
что предотвратит сопоставление оператора(), даже если он будет переопределен. Можете ли вы также подтвердить, что это правильно?
Как то Демо.
если одним операндом является void(..)
, то оператор запятой, предоставленный пользователем, действительно не используется.
Я добавил участника в MyPtr
, чтобы получить больше информации. Затем фактическая оценка выражения говорит вам, что происходит:
#include <iostream>
#include <typeinfo>
struct MyPtr {
int value;
MyPtr(int x) : value(x) {}
double operator,(int Input) {
std::cout << "Operator, called value = " << value
<< " Input = " << Input << std::endl;
return 1.0;
}
MyPtr operator*() {
std::cout << "operator* called value = " << value << std::endl;
return *this;
}
MyPtr operator++() {
std::cout << "operator++ called value = " << value << 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() {
Foo f1{10};
Foo f2{20};
++begin(f1), *begin(f2), std::true_type{};
++begin(f1), *begin(f2), std::false_type{};
}
operator++ called value = 10
operator* called value = 20
Operator, called value = 20 Input = 1
operator++ called value = 10
operator* called value = 20
Operator, called value = 20 Input = 0
Ваша "Теория" верна. Давайте удалим ++
и *
, чтобы было проще, тогда вы можете думать о f1,f2,std::true_type{}
как о f1.operator,( f2.operator,(std::true_type{})
. std::true_type
имеет operator bool
и bool
может быть неявно преобразовано в int
. Чтобы проиллюстрировать это, я также добавил в код пример с false_type
.
operator bool
можно найти здесь как operator value_type
, потому что std::true_type
— это просто псевдоним для std::integral_constant<bool,true>
.
что предотвратит сопоставление оператора(), даже если он будет переопределен. Можете ли вы также подтвердить, что это правильно?
Да. Невозможно реализовать перегрузку оператора запятой для void
.
*begin и ++begin здесь, чтобы (в конечном итоге) создать трейт для проверки, поддерживает ли тип итераторы. Я согласен, что они лишние для этого вопроса. Однако как в вашем ответе получается, что MyPtr{},MyPtr{} является двойным? Оператор запятой ожидает int, а не MyPtr. Кроме того, вы правы, оцениваемые контексты проще в использовании.
вы могли бы легче увидеть, что происходит, фактически оценивая выражения, а не используя их только в невычисленном контексте