#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 触发表达式只能出现在模板参数中。
SFINAE 在表达式上最简单的位置是 noexcept 说明符:
struct B {
template<typename... Args>
B(const Args&... args) noexcept(noexcept(A(args...))) : a(args...) { }
// `noexcept(false && noexcept(A(args...)))` if you need to keep it `noexcept(false)` for whatever reason
A a;
};
在 C++20 中,您可以使用约束和需求表达式来做到这一点:
struct B {
B(const auto&... args) requires(requires { A(args...); }) : a(args...) { }
A a;
};