2016-06-16 3 views
2

Интересно, если есть обходной путь такая ситуация:Инициализация анонимного переменной-члена класса с станд :: функция

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::functionstatic, и такой код работает, но требует non-constexpr/const члена, потому что станд :: функция имеет non-trivial destructor - что это плохо, потому что требуется исходный файл, который требует создания такого файла, что требует некоторого эффекта и уничтожения моей красивой иерархии классов только для заголовка! (Я имею в виду, я мог бы лениться и определить эту переменную в заголовке, но тогда возникает проблема с множественным определением). Я знаю, что это может быть плохой дизайн (я просто проверяю вещи), но есть ли у вас какие-либо идеи о том, как решить проблему без привлечения исходных файлов?

+1

Вам разрешено пересылать вложенные классы. Таким образом, вы можете присвоить классу имя и ссылаться на него вместо использования 'decltype' в элементе данных. Или полностью разделите определение вложенного класса и элемента данных. Я не уверен, что это слияние покупает вас. –

+0

@Johannes Schaub Теперь, когда я смотрю на него, я не знаю, почему я хотел, чтобы это было анонимно. Спасибо за ответ :) – xinaiz

ответ

1

Хотя ваш пример надуманный, есть времена, когда я нужен (или его более удобно), чтобы инициализировать сложные объекты подобным образом.

Но зачем использовать 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); Я бы просто дал классу имя.

+0

Может быть, потому что тогда initB может быть переназначен, как функция ptr, любой другой std :: function <...>, включая пользовательские? – lorro

+0

@lorro: Но в этом случае, поскольку initB и B инициализируются во время построения A, нет никакого преимущества в использовании std :: function <>. Было бы иначе, если бы, например, initB был статичным, потому что теоретически ему было назначено новое значение, влияющее на построение новых экземпляров A (т. Е. InitB был бы фабрикой, используемой для построения экземпляров B). – Steven

0

Я чувствую, что я как-то подрываю ваши намерения, но если вы инициализируете переменные в конструкторе, вы можете заставить все работать.

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

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