Несколько запутался с проверкой типов в SFINAE. Допустим, есть:
class Foo
{
public:
std::string member;
std::string member2;
template <
typename T, // Parameter 1.
typename U, // Parameter 2.
typename Enable = typename std::enable_if <
std::is_constructible<std::string, T>::value &&
std::is_constructible<std::string, U>::value>::type>
Foo(T&& member, U&& member2) :
member{std::forward<T>(member)},
member2{std::forward<U>(member2)}
{}
};
Не пойму, что нужно использовать, std::is_constructible
или же std::is_convertible
или std::is_same
? Про последний, так понимаю жесткое совпадение нам обеспечено, можно еще std::decay
только добавить. Однако хотелось бы строку инициализировать С-массивом или, например, вектор через std::initializer_list
. Про std::is_convertible
знаю, что пропустит, например, преобразование float
в int
, однако в таком коде:
template<class D>
impl_ptr(pointer p, D&& d,
typename std::enable_if<
std::is_convertible<D, deleter_type>::value,
dummy_t_
>::type = dummy_t_()) noexcept
: ptr_(std::move(p), std::forward<D>(d)) {}
используется (этот пример - конструктор smart-указателя для реализации pimpl, D
и deleter_type
- это удалители, ptr_
имеет тип std::unique_ptr
).
std::is_convertible
подразумевает именно и только неявные преобразования, со всеми сопутствующими ограничениями, налагаемыми на неявные преобразования. Он не будет принимать во внимание конвертирующие конструкторы и операторы приведения типа, помеченные как explicit
. Он не будет выполнять более одного пользовательского преобразования в последовательности преобразований.
std::is_constructible
напрямую рассматривает именно конструкторы, причем независимо то того, помечены ли они как explicit
.
То есть разделение тут совершено четкое и [примерно] соответствует разнице между прямой инициализацией T a(b)
и инициализацией копированием T a = b
. Даже в С++17 различия между этими формами инициализации не сводятся только к explicit
.
Выбирайте, что именно вам нужно в вашем случае.
У вас сейчас is_constructible
, что фактически вытаскивает наружу все конструкторы std::string
, включая конструкцию из аллокатора. Вам нужна такая возможность? Подозреваю, что исходный замысел был в том, чтобы разрешить только конструкцию из разнообразных видов строк. А тогда уместнее именно is_convertible
.
В подобных случаях лучше использовать std::is_constructible
, потому что вы передаёте аргумент в конструктор, а значит и проверять вам нужно существование конструктора для данных аргументов.
Но для конкретно приведённого примера лучше использовать string_view (если доступен), или принимать стоки по значению и передавать через std::move
. Вариант с шаблонной реализацией создаёт больше проблем, чем пользы.
А std::is_convertible
для удалителей в умных указателях используется из-за того, что удалителем может быть лямбда, которая неявно преобразуется в указатель на функцию, но указатель на функцию не конструируется напрямую из лямбды.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
В файле AddressSanitizercpp есть функция AddressSanitizer::instrumentStoreInstruction(
Какие функции в Visual Studio (помимо system("pause");) останавливают закрытие консоли
Имееться код hash-алгоритмаТак как его надо исследовать, необходимо его запустить (для начала)
Привет всемВозникла задача, на основе XML и XSD динамически подгружать интерфейс