【问题标题】:Trouble using SFINAE to switch constructors [duplicate]使用 SFINAE 切换构造函数时遇到问题 [重复]
【发布时间】:2019-05-04 00:43:10
【问题描述】:

我有两个构造函数,我想根据模板参数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&lt;true&gt;

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

Base&lt;false&gt;。我能找到的其他变体(包括thisthisthis)都不起作用。如何根据yes选择使用哪个构造函数?

【问题讨论】:

  • 在一个非模板化的构造函数中写if constexpr (yes) { /* ... */ } else { /* ... */ }不是更简单吗?这将是同样的事情。由于您遇到编译器问题,您的目标是什么版本的 C++?你可能需要 C++11,对于if constexpr,你需要 C++17
  • 我会,但它的初始化列表实际上在这些构造函数之间有所不同。我目前的目标是 C++14,但如果有一个可行的解决方案,我可以切换到 C++17。

标签: c++ sfinae


【解决方案1】:

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

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 */ }

这就是编译器对两个构造函数的签名的看法。两者都是具有单个参数的模板,因此出于重载决议的目的,两个构造函数具有相同的签名,这不会比声明两个“Base(int foo)”构造函数更好。如果你声明,你会得到同样的错误:

Base(int foo=0)

Base(int foo=1)

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

有几种传统的技巧可以解决这个问题。 C++ 库本身的一个常见设计模式是声明一些辅助空类并将它们用作附加参数来消除不同方法的歧义,从而实现重载解析。例如,使用std::in_place_t 选择std::optionalstd::in_place_type_t 的特定重载构造函数,以获得std::variant's constructor 的等效功能。

在您的情况下,我们可以完全自动地使用占位符参数,并结合委托构造函数:

#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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    相关资源
    最近更新 更多