Вы можете ввести преднамеренную ошибку двусмысленности, когда присутствуют и конструктор перемещения, и конструктор копирования. Это позволяет нам проверить наличие конструктора перемещения.
В последние годы по мере изменения компиляторов разные решения работают, а затем ломаются. Это работает с clang 3.5.0. Я надеюсь, что он будет работать и на старых, и на новых компиляторах, но я не эксперт по стандарту.
Кроме того, этот ответ требует дополнительной работы, чтобы закончить его, но я проверил основную идею.
Во-первых, легко сказать, есть ли копирующий конструктор. Если конструктора копирования нет, то легко определить, есть ли конструктор перемещения. Проблема состоит в том, что при наличии есть конструктора копирования проверить, есть ли также конструктор перемещения. Это задача, на которой я сосредоточусь здесь.
Поэтому достаточно рассматривать только типы, у которых есть конструктор копирования, и проверять наличие конструктора перемещения. В оставшейся части этого вопроса я предполагаю наличие конструктора копирования.
Я проверяю конструктор перемещения, вызывая ошибку неоднозначности, когда присутствуют оба вида конструктора, а затем (ab) использую SFINAE для проверки наличия этой неоднозначности.
Другими словами, наша задача состоит в том, чтобы проверить разницу между следующими типами:
struct CopyOnly {
CopyOnly (const CopyOnly&); // just has a copy constructor
};
struct Both {
Both (const Both&); // has both kinds of constructor
Both (Both&&);
};
Для этого сначала определите класс Converter<T>
, который утверждает, что может преобразовывать себя в два вида ссылок. (Нам никогда не понадобится их реализовывать)
template<typename T>
struct Converter {
operator T&& ();
operator const T& ();
};
Во-вторых, рассмотрите эти строки:
Converter<T> z;
T t(z);
Вторая строка пытается построить T
. Если T
равно CopyOnly
, то t
будет выполнено через конструктор копирования, а соответствующая ссылка для передачи конструктору копирования будет извлечена из метода operator const CopyOnly &()
Converter<CopyOnly>
. Пока это довольно стандартно. (Я думаю?)
Но если T
равно Both
, т. е. у него также есть конструктор перемещения, будет ошибка неоднозначности. Доступны оба конструктора T
, поскольку для обоих доступны преобразователи (преобразователи из z
), поэтому возникает неоднозначность. (Кто-нибудь из языковых юристов может подтвердить, что это полностью стандартно?)
Эта логика применима и к new T( Converter<T>{} )
. Это выражение имеет тип тогда и только тогда, когда T
не имеет конструктора перемещения. Поэтому мы можем обернуть decltype
вокруг этого и использовать это в SFINAE.
Я закрываю двумя перегрузками baz<T>
. Выбранная перегрузка будет зависеть от того, соответствует ли T
CopyOnly
или Both
. Первая перегрузка действительна только в том случае, если new T( Converter<T>{} )
определено корректно, т. е. если нет ошибки неоднозначности, т. е. если нет конструктора перемещения. Вы можете указать разные типы возврата для каждой перегрузки, чтобы сделать эту информацию доступной во время компиляции.
template<typename T>
std:: true_type
baz (decltype( new T( Converter<T>{} ) )) {
cout << __LINE__ << endl;
return {};
}
template<typename U>
std:: false_type
baz (
const volatile // const volatile to tie break when both forms of baz are available
U *) {
cout << __LINE__ << endl;
return {};
}
baz
следует вызывать так:
baz<JustCopy>((JustCopy*)nullptr);
baz<Both>((Both*)nullptr);
И вы могли бы обернуть это как-то так:
template<typename T>
struct has_move_constructor_alongside_copy {
typedef decltype(baz<T>((T*)nullptr)) type;
};
Нужно многое сделать, чтобы привести его в порядок, и я уверен, что эксперты SFINAE могли бы значительно его улучшить (пожалуйста, сделайте!). Но я думаю, что это решает основную проблему, проверяя наличие конструктора перемещения, когда мы уже знаем, что конструктор копирования присутствует.
person
Aaron McDaid
schedule
08.01.2015
T t2{ std:: move(t1) };
. Это выражение вернется к конструктору копирования, если он присутствует. Итак, что именно вы спрашиваете? Вы хотите конкретно проверить, был ли определен явный конструктор перемещения (довольно узкий тест)? Или, в более широком смысле, вы хотите проверить, может ли он быть построен из r-значения (легко проверить, будет включать почти все типы, у которых есть конструктор копирования)? - person Aaron McDaid   schedule 09.01.2015T :: T(T&&)
... - person Aaron McDaid   schedule 09.01.2015