使用Sfinae切换构造函数的麻烦

Trouble using SFINAE to switch constructors

本文关键字:麻烦 构造函数 Sfinae 使用      更新时间:2023-10-16

我有两个构造函数,我想根据模板参数 yes

在之间选择这些构造函数
template <bool yes>
class Base {
public:
  template<typename std::enable_if< yes, int>::type = 0>
  Base() { /* yes */ }
  template<typename std::enable_if<!yes, int>::type = 0>
  Base() { /* no */ }
};

我感到困惑为什么会产生编译器错误,

failed requirement '!true'; 'enable_if' cannot be used to disable this declaration

Base<true>

no type named 'type' in 'std::__1::enable_if<false, int>'; 'enable_if' cannot be used to disable this declaration

Base<false>上。我都无法找到包括此内容的其他变体,这也没有。如何根据yes选择哪个构造函数?

这里有几个问题。首先是默认模板模板参数的语法是错误的,应该是:

template <bool yes>
class Base {
public:
  template<typename T=std::enable_if< yes, int>::type>
  Base() { /* yes */ }
  template<typename T=std::enable_if<!yes, int>::type>
  Base() { /* no */ }
};

,但这也不是可以工作的,因为默认参数值不是模板签名的一部分,因此,大概,这等同于:

  template<typename T>
  Base() { /* yes */ }
  template<typename T>
  Base() { /* no */ }

这就是两个构造师的签名对编译器的外观。两者都是具有单个参数的模板,因此出于超载分辨率的目的,两个构造函数都具有相同的签名,并且这不会比宣布两个"基础(int foo("构造函数更好。如果您声明:

您会遇到相同的错误
Base(int foo=0)

Base(int foo=1)

构造函数。两个构造函数,都具有相同的签名。默认值不是签名的一部分。

有几种传统的黑客攻击。C 库本身中的一个常见设计模式是声明某些助手空类,并将其用作其他参数,以消除歧义不同的方法,以解决过载分辨率。例如,使用std::in_place_t选择std::optional构造函数的等效功能的CC_6或std::in_place_type_t的特定重载构造函数。

在您的情况下,我们可以与委派的构造函数一起使用完全自动的占位符参数:

#include <iostream>
struct bool_true {};
struct bool_false {};
template<bool value> class bool_value;
template<>
struct bool_value<true> {
    typedef bool_true type;
};
template<>
struct bool_value<false> {
    typedef bool_false type;
};
template<bool v>
using bool_value_t=typename bool_value<v>::type;

template <bool yes>
class Base {
public:
    Base() : Base{ bool_value_t<yes>{} } {}
    Base(const bool_true &)
    {
        std::cout << "Yes" << std::endl;
    }
    Base(const bool_false &)
    {
        std::cout << "No" << std::endl;
    }
};
int main()
{
    Base<true> t;
    Base<false> f;
    return 0;
}