用std::function初始化匿名class成员变量

Initialization of anonymous class member variable with std::function

不知道有没有办法解决这种情况:

class A
{
    class
    {
    public:
        void setValue(int val) {i=val;}
    private:
        int i;
    } B = initB(10);

    std::function<decltype(B)(int)> initB = [this](int value)
                                            {decltype(B) temp;
                                             temp.setValue(value);
                                             return temp;};
}


//...
    A a; //crash
//...

我想这是初始化顺序造成的。变量 B 是通过调用未初始化的 std::function 实例来初始化的,因此发生了崩溃。按照我的逻辑,解决方法是先初始化 std::function,然后初始化成员 B。但是,这样的代码是无效的:

class A
    {
        //error: 'B' was not declared in this scope
        std::function<decltype(B)(int)> initB = [this](int value)
                                                {decltype(B) temp;
                                                 temp.setValue(value);
                                                 return temp;};
        class
        {
        public:
            void setValue(int val) {i=val;}
        private:
            int i;
        } B = initB(10);
    }

我尝试制作 std::function static,这样的代码有效,但需要 non-constexpr/const 成员,因为 std::function 有 non-trivial destructor -这很糟糕,因为这需要源文件,这需要创建这样的文件,这需要一些努力和破坏我美丽的 header-only class 层次结构! (我的意思是,我可以偷懒并在 header 中定义此变量,但随后会出现多重定义问题)。我知道这可能是一个糟糕的设计(我只是在测试),但是你知道如何在不涉及源文件的情况下解决这个问题吗?

我觉得我在某种程度上颠覆了你的意图,但如果你在构造函数中初始化变量,你可以使事情正常进行。

#include <functional>

class A
{
  class
  {
   public:
    void setValue(int val) {i=val;}
   private:
    int i;
  } B;

  std::function<decltype(B)(int)> initB;

 public:
  A() {
    initB = [this](int value)
            {decltype(B) temp;
             temp.setValue(value);
             return temp;};
    B = initB(10);
  }
};

int main() {
  A a;
}

尽管您的示例是人为设计的,但有时我需要(或更方便地)以类似方式初始化复杂对象。

但是,为什么要使用 std::function<>?为什么不直接使用函数?

class A
{
    class
    {
    public:
        void setValue(int val) { i = val; }
    private:
        int i;
    } B = initB(10);

    static decltype(B) initB(int value)
    {
        decltype(B) temp;
        temp.setValue(value);
        return temp; 
    }
};

虽然,我通常不会使用 decltype(B);我只想给 class 起个名字。

A::initB 是一个值。它没有在您调用它的地方初始化,因为初始化是按照您指定成员字段的顺序完成的(粗略地说)。您可以通过执行以下有效的方法来验证这一点:

#include <iostream>
#include <functional>
using namespace std;

template<typename T, typename U>
T set(T& tgt, const U& src)
{
    new(&tgt) T(src);
    return tgt;
}

class A
{
    class
    {
    public:
        void setValue(int val) {i=val;}
    private:
        int i;
    } B = set(initB, [this](int value)
                        {decltype(B) temp;
                         temp.setValue(value);
                         return temp;})(10);

    std::function<decltype(B)(int)> initB;
};


int main() {
    A a;
}