我想 SFINAE 禁用类模板构造函数 - 但问题是启用-禁用条件是该类的特征。特别是,我想仅当该类中存在匹配构造函数模板参数的特定类方法时才启用该构造函数。
一个简化的例子:
struct S
{
std::size_t n = 0;
void set_value(int i) { n = i; }
void set_value(const std::string & s) { n = s.size(); }
template <class T, class = decltype(std::declval<S>().set_value(std::declval<T>()))>
S(T && x)
{
set_value(std::forward<T>(x));
}
};
该解决方案适用于 GCC,据称适用于 MSVC,但不适用于 Clang。在我看来 Clang 就在这里,因为在类定义中还没有定义类,所以 std::declval<S>()
不应该在这里工作。所以我的想法是将构造函数定义移出类定义:
struct S
{
std::size_t n = 0;
void set_value(int i) { n = i; }
void set_value(const std::string & s) { n = s.size(); }
template <class T, class>
S(T &&);
};
template <class T, class = decltype(std::declval<S>().set_value(std::declval<T>()))>
S::S(T && x)
{
set_value(std::forward<T>(x));
}
但这在 GCC 和 MSVC 中不起作用。该解决方案看起来也有些可疑,因为我首先无条件声明了该构造函数,然后才引入了 SFINAE。我的问题是 - 是否有可能在 C++11/14/17 中解决该任务?一个特定的任务是,只有当一个类也有一个匹配的 setter 方法时,它才应该有一个构造函数。显然,可以为每个 setter 方法重载手动定义一个非模板构造函数,但那样繁琐且难以维护。
但我也对更一般的任务感兴趣 - SFINAE 通过该类的特征启用构造函数或其他类方法(需要完整的类定义)。
另外,在我的示例中哪个编译器更合适——GCC/MSVC 还是 Clang?
最佳答案
您可以引入另一个具有默认值 S
的模板参数,并将其用于 SFINAE。例如。
template <class T, class X = S, class = decltype(std::declval<X>().set_value(std::declval<T>()))>
S(T && x)
{
set_value(std::forward<T>(x));
}
LIVE
关于c++ - 基于该类的特征禁用类构造函数的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65715675/