c++ - 检测(可能是抽象的)基类的 protected 构造函数

标签 c++ templates c++11 template-meta-programming perfect-forwarding

我正在试验 C++11 的新特性。在我的设置中,我真的很想使用继承构造函数,但不幸的是还没有编译器实现这些。因此,我试图模拟相同的行为。我可以这样写:

template <class T>
class Wrapper : public T {
    public:
    template <typename... As>
    Wrapper(As && ... as) : T { std::forward<As>(as)... } { }
    // ... nice additions to T ...
};

这很有效……大多数时候。有时代码使用 Wrapper类必须使用 SFINAE 来检测这样的 Wrapper<T>可以构建。但是存在以下问题:就重载决议而言,Wrapper<T> 的构造函数将接受任何参数 - 但如果类型为 T,则编译失败(这 SFINAE 涵盖)不能用这些来构造。

我尝试使用 enable_if 有条件地启用构造函数模板的不同实例化。

    template <typename... As, typename std::enable_if<std::is_constructible<T, As && ...>::value, int>::type = 0>
    Wrapper(As && ... as) // ...

只要满足以下条件就可以正常工作:

  • T 的适当构造函数是 public
  • T不是抽象的

我的问题是:如何摆脱上述两个约束?

我试图通过检查(使用 SFINAE 和 sizeof() )是否表达式 new T(std::declval<As &&>()...) 来克服第一个问题。格式正确 Wrapper<T> .但这当然行不通,因为派生类可以使用其基类的 protected 构造函数的唯一方法是在成员初始化列表中。

对于第二个,我完全不知道——它是我需要的更多,因为有时它是 Wrapper实现了T的抽象函数,使其成为一个完整的类型。

我想要一个解决方案:

  • 按标准正确
  • 适用于任何 gcc-4.6.*、gcc-4.7.* 或 clang-3.*

谢谢!

最佳答案

这似乎在我的本地 GCC(4.7,由 rubenvb 提供)上运行良好。不过,ideone 上的 GCC 会打印几个“已实现”的编译器内部错误。

我不得不公开 Experiment 类的“实现细节”,因为出于某些原因(这听起来像一个错误),我的 GCC 版本提示它们是私有(private)的,即使只有类本身使用它。

#include <utility>

template<typename T, typename Ignored>
struct Ignore { typedef T type; };

struct EatAll {
  template<typename ...T>
  EatAll(T&&...) {}
};

template<typename T>
struct Experiment : T {
public:
  typedef char yes[1];
  typedef char no[2];

  static void check1(T const&);
  static void check1(EatAll);

  // if this SFINAE fails, T accepts it
  template<typename ...U>
  static auto check(int, U&&...u)
    -> typename Ignore<no&, 
        decltype(Experiment::check1({std::forward<U>(u)...}))>::type;

  template<typename ...U>
  static yes &check(long, U&&...);

public:
  void f() {}
  template<typename ...U, 
           typename std::enable_if<
             std::is_same<decltype(Experiment::check(0, std::declval<U>()...)),
                          yes&>::value, int>::type = 0>
  Experiment(U &&...u):T{ std::forward<U>(u)... }
  {}
};

// TEST

struct AbstractBase {
  protected:
    AbstractBase(int, float);
    virtual void f() = 0;
};

struct Annoyer { Annoyer(int); };

void x(Experiment<AbstractBase>);
void x(Annoyer);

int main() {
  x({42});
  x({42, 43.f});
}

更新:该代码也适用于 Clang。

关于c++ - 检测(可能是抽象的)基类的 protected 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12079711/

相关文章:

templates - Google Go 文本模板中范围最后一个元素的特殊情况处理

c++ - 使用开放式寻址将节点插入哈希表[优化逻辑]

c++ - 模板和 is_same() 不起作用?

c++ - 将boost数组转换为opencv mat

c++ - 使用命令行参数从 txt 文件中提取并在 C++ 中运行特定类

.net - 在 Label 的内容中明确使用 TextBlock 会使 ContentPresenter 行为异常

c++ - 具有范围限定符的模板语法的含义

c++ - 在编译时将 mpl::vector_c 复制到静态数组

C++ : convert vector to tuple

c++ - 如何用 NaN 元素初始化双矩阵?