Привет!
Разбираюсь с value category, читаю
http://www.stroustrup.com/terminology.pdf:
iM: has identity and cannot be moved from
im: has identity and can be moved from
Im: does not have identity and can be moved from
The fourth possibility (“IM”: doesn’t have identity and cannot be moved) is not useful in C++
Я не понял есть ли в языке выражения которые относятся с категории IM?
Если есть, то хотелось бы узнать несколько примеров таких выражений.
Здравствуйте, Максим Рогожин, Вы писали:
МР>Привет!
МР>Разбираюсь с value category, читаю http://www.stroustrup.com/terminology.pdf:
МР>iM: has identity and cannot be moved from
МР>im: has identity and can be moved from
МР>Im: does not have identity and can be moved from
МР>The fourth possibility (“IM”: doesn’t have identity and cannot be moved) is not useful in C++
МР>Я не понял есть ли в языке выражения которые относятся с категории IM?
Ну ясно же написано: "is not useful in C++" — как это можно еще интерпретировать?
Вот тебе картинка прямо из стандарта. Любое выражение в C++ относится к одной из трех конкретных категорий, соответствующих листьям этого графа (lvalue, xvalue, prvalue). Узлы более верхних уровней — это группировки. Так вот lvalue — это iM, xvalue — im, prvalue — Im. Узлы второго уровня: glvalue объединяет все "i", rvalue объединяет все "m". Что такое IM, мне и представить сложно — какая-то вещь в себе, которую никак нельзя использовать.
Здравствуйте, rg45, Вы писали:
R>Что такое IM, мне и представить сложно — какая-то вещь в себе, которую никак нельзя использовать.
Если я правильно понимаю, то эту вещь всё-таки можно использовать, хотя польза от неё и не слишком велика. Скажем, есть
код приблизительно такого вида:
#include <iostream>
namespace N
{
void foo()
{
std::cout << "N::foo()" << std::endl;
}
void bar(const int argument)
{
std::cout << "N::bar(int), argument = " << argument << std::endl;
}
}
int main()
{
N::foo();
N::bar(42);
N::foo();
N::bar(108);
N::foo();
}
...и хочется посчитать количество вызовов всех функций в пространстве имён
N (или каком-нибудь другом), внеся минимальные изменения в существующий код. Это можно сделать, вообще не изменяя кода самих функций. Например,
так:
#include <iostream>
template <typename SomeType>
class Counter final
{
private:
static auto& value() noexcept
{
static std::size_t counter;
return counter;
}
public:
Counter() = delete;
Counter(const Counter&) = delete;
Counter(Counter&&) = delete;
~Counter() = delete;
Counter& operator=(const Counter&) = delete;
Counter& operator=(Counter&&) = delete;
static auto Value() noexcept
{
return value();
}
static auto Increment() noexcept
{
return ++value();
}
};
template <typename DerivedCounter>
class FunctionCallCounter
{
private:
using InternalCounter = Counter<DerivedCounter>;
public:
FunctionCallCounter() noexcept
{
(void)InternalCounter::Increment();
}
FunctionCallCounter(const FunctionCallCounter&) = delete;
FunctionCallCounter(FunctionCallCounter&&) = delete;
FunctionCallCounter& operator=(const FunctionCallCounter&) = delete;
FunctionCallCounter& operator=(FunctionCallCounter&&) = delete;
static auto NumberOfCalls() noexcept
{
return InternalCounter::Value();
}
};
struct N final : public FunctionCallCounter<N>
{
void foo()
{
std::cout << "N::foo()" << std::endl;
}
void bar(const int argument)
{
std::cout << "N::bar(int), argument = " << argument << std::endl;
}
};
int main()
{
N{}.foo();
N{}.bar(42);
N{}.foo();
N{}.bar(108);
N{}.foo();
std::cout << "Number of function calls = " << N::NumberOfCalls() << std::endl;
}
Сущности
N{} здесь как раз-таки представляют собой IM (doesn’t have identity and cannot be moved).