Использование SFINAE в конструкторе, чтобы проверить, существует ли конструктор типа члена

#include <string>
#include <type_traits>

struct A {
    A(int) {}
};

template<typename... Args>
auto make_A(const Args&... args) -> decltype(A(args...)) {
    return A(args...);
}

struct B {
    template<typename... Args
        //std::enable_if ?
    >
    B(const Args&... args) : a(args...) { } 
    
    A a;
};


int main() {
    A a1 = make_a(123);
    //A a2 = make_a(std::string("123")); // no make_a<std::string>
    
    B b1(123); // ok 
    B b2(std::string("123")); // fails because A(std::string) does not exist,
                              // but should fail already because there is no B(std::string)
}

Таким образом, код A может быть создан только с аргументом int.

make_a использует SFINAE, поэтому экземпляр make_a<Args...> создается только тогда, когда A::A(Args...) существует. Это делается с помощью decltype() в возвращаемом типе, где args доступен.

Можно ли аналогичным образом ограничить шаблонный конструктор B::B<Args...>? Здесь выражение, запускающее SFINAE, может находиться только в аргументах шаблона.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В C++20 вы можете сделать это с помощью ограничения и выражения require:

struct B {
    B(const auto&... args) requires(requires { A(args...); }) : a(args...) { }
    A a;
};

Или, если вы не хотите использовать спецификатор noException, у вас не будет доступа к args, и вместо него вы можете использовать std::declval<const Args&>():

template<typename... Args,
         decltype(static_cast<void>(A(std::declval<const Args&>()...)), nullptr) = nullptr>
B(const Args&... args) : a(args...) { }

Я сейчас использую class = std::void_t<decltype(A(std::declval<Args>()...))>

tmlen 23.08.2024 13:21

Это неправильно. Спецификатор noException объявления шаблона функции не участвует в SFINAE. Он создается только после того, как функция выбрана путем разрешения перегрузки, и в этот момент это серьезная ошибка, если она содержит недопустимое выражение. См. eel.is/c++draft/temp.deduct.general#7

Brian Bi 24.08.2024 04:31

@BrianBi Вы правы. Я думал о noexcept(noexcept(...)) -> decltype(...) и думал, что noexcept делает замену неудачной, но это был decltype.

Artyer 24.08.2024 09:43

Другие вопросы по теме

Использование if-constexpr и концепций для обнаружения экземпляра определенного типа расширенной политики
Почему квалификатор const игнорируется при применении к выведенной ссылке Lvalue в C++?
Создание декартова произведения на основе аргумента шаблона целочисленного диапазона
Почему выведение std::call_once не удалось и возникла ошибка «не удалось вывести параметр шаблона ‘_Callable’»
Невозможно получить доступ к специализации класса шаблона через универсальную ссылку
Вывести класс шаблона с уменьшенным количеством параметров шаблона
Как добавить собственный класс CSS в навигационное меню WooCommerce MyAccount?
Руководства по выводу кортежей в C++17 (CTAD): неявно генерируемые и определяемые пользователем
Как ограничить функцию шаблона определенными типами?
Кратко сопоставьте переменные времени выполнения с параметрами шаблона для _многих_ функций