#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)
}
Assim, o código A
só pode ser construído com um int
argumento.
make_a
usa SFINAE, para que make_a<Args...>
só seja instanciado quando A::A(Args...)
existir. Ele faz isso usando decltype()
o tipo de retorno, onde args
está disponível.
Também é possível restringir o construtor de modelo B::B<Args...>
de maneira semelhante? Aqui, a expressão de acionamento do SFINAE só pode estar nos argumentos do modelo.
Em C++20 você pode fazer isso com uma restrição e uma expressão requer:
Ou se não quiser usar o especificador noexcept, você não terá acesso
args
e poderá usarstd::declval<const Args&>()
: