2017-05-02 4 views
1

Der folgende Code:var in seinem eigenen initializer verwendete

auto getConnection(const std::string &name) { 
     constexpr const std::size_t id{findFactoryId(_factories, name)}; 
     const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second; 
     for (auto &connection : _connections[id]) 
      if (connection.first) { 
       connection.first = false; 
       decltype(factory()) &res = std::experimental::any_cast(connection.second); 
       return res; 
      } 
     _connections[id].emplace_back(std::make_pair<bool, std::experimental::any>(false, factory())); 
     decltype(factory()) &res = std::experimental::any_cast(_connections[id].back().second); 
     return res; 
    } 

mit Klirren ++ kompilieren, aber mit g ++ gibt diesen Fehler:

In file included from main.cpp:2:0: 
src/core/include/connectionpool.h: Dans la fonction membre « auto Core::ConnectionPool<Connectors>::getConnection(const string&) »: 
src/core/include/connectionpool.h:28:79: erreur : the value of « id » is not usable in a constant expression 
      const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second; 
                       ^~ 
src/core/include/connectionpool.h:27:41: note : « id » used in its own initializer 
      constexpr const std::size_t id{findFactoryId(_factories, name)}; 
             ^~ 
src/core/include/connectionpool.h:28:81: erreur : the value of « id » is not usable in a constant expression 
      const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second; 
                       ^
src/core/include/connectionpool.h:27:41: note : « id » used in its own initializer 
      constexpr const std::size_t id{findFactoryId(_factories, name)}; 
             ^~ 
src/core/include/connectionpool.h:28:81: note : in template argument for type « unsigned int » 
      const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second; 
                       ^

ich jenen Befehl zu kompilieren:

(clan)g++ -std=c++14 -O2 -Wall -pedantic -Wextra main.cpp 

mit g++ v6.3.1 und clang++ v3.9.1

Der einzige Link, der meinem Problem entspricht, ist ein Fehlerbericht für gcc4.9 (der gelöst ist): https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59937.

Ein minimales Arbeitsbeispiel ist verfügbar here.

Von was ich von gcc Fehlermeldung verstanden habe, sollte ich keinen Fehler haben: id wird nicht verwendet, um sich selbst zu initialisieren.

Sollte dieser Code einen Fehler ergeben oder nicht?

Wenn es einen Fehler auslösen sollte, was könnte ich tun, um den Fehler zu beheben?

Vielen Dank für Ihre Antworten.

Der vollständige Code:

#include <iostream> 
#include <vector> 
#include <memory> 
#include <string> 
#include <functional> 
#include <utility> 
#include <type_traits> 
#include <tuple> 
#include <experimental/any> 

template <class F, class... Ts> 
constexpr void for_each_in_tuple(const std::tuple<Ts...> &tuple, F f) { 
    for_each_in_tuple(tuple, f, std::make_index_sequence<sizeof...(Ts)>()); 
} 


template <class F, class... Ts, std::size_t... Is> 
constexpr void for_each_in_tuple(const std::tuple<Ts...> &tuple, F f, std::index_sequence<Is...>) { 
    using expander = int[]; 
    (void) expander{0, ((void)f(Is, std::get<Is>(tuple)), 0)...}; 
} 

template <typename... Connectors> 
class ConnectionPool { 
    public: 
     auto getConnection(const std::string &name) { 
      constexpr const std::size_t id{findFactoryId(_factories, name)}; 
      const auto factory = std::get<std::integral_constant<std::size_t, id>{}>(_factories).second; 
      return factory(); 
     } 

    private: 
     struct foo { 
      constexpr foo(std::size_t &i, const std::string &name) : i(i), name(name) {} 
      template <class T> 
      constexpr void operator()(const std::size_t is, const T pair) { 
       i = name == pair.first ? is : i; 
      } 
      std::size_t &i; 
      const std::string &name; 
     }; 

     template <class Tuple> 
     static constexpr std::size_t findFactoryId(Tuple &tup, const std::string &name) { 
      std::size_t i = 0; 
      for_each_in_tuple(tup, foo(i, name)); 
      return i; 
     } 

     std::tuple<std::pair<std::string, std::function<Connectors()>>...> _factories; 
}; 


int main() 
{ 
    return 0; 
} 

EDIT

ändern Link zu minimalen Arbeitsbeispiel: eine Funktion fehlte.

EDIT 2

hinzufügen minimales Arbeitsbeispiel in der Post

+2

Der Fehler ist ziemlich klar, 'findFactoryId()' 'nicht constexpr' von gcc Sicht liefert, sollten Sie besser schreiben ihren Körper hier. – VTT

+1

Können Sie das Codebeispiel in [MCVE] vereinfachen? –

Antwort

4

Das Problem auf dieser Linie ist:

constexpr const std::size_t id{findFactoryId(_factories, name)}; 

Die Initialisierer einer constexpr Variable ein konstanter Ausdruck sein muss. In einem konstanten Ausdruck können Sie den Zeiger this nicht verwenden. Sie verwenden implizit den Zeiger this, indem Sie auf _factories verweisen, der ein Datenelement ist.

N4296 [expr.const] ¶2

A conditional-expressione is a core constant expression unless the evaluation of e ... would evaluate one of the following expressions:

  • this , except in a constexpr function or a constexpr constructor that is being evaluated as part of e ;
  • ...

Überraschenderweise beiden Compiler sind glücklich, wenn wir einfach ein explizites this verwenden:

constexpr const std::size_t id{findFactoryId(this->_factories, name)}; 

Aber ich glaube nicht, dass konforme ist. Hier ist eine portable Lösung:

const auto _this = this; 
constexpr const std::size_t id{findFactoryId(_this->_factories, name)}; 
+0

Also warum kompilieren kompilieren ohne Fehler, wenn es nicht sollte? Ist das ein Bug im Klang? – nefas

+0

Ja.Soweit ich das beurteilen kann, war es in C++ 11 erlaubt, aber das war ein [Defekt] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1369) . Es sollte "dies" in einer "constexpr" -Funktion und nicht in einem konstanten Ausdruck möglich sein. C++ 14 [entspannt 'constexpr'] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html) verschärfte die Regeln für" das ", aber es scheint so Implementierungen haben in ihrer Aufnahme variiert. – Oktalist

+0

@Oktalist Ich möchte diese Problemumgehung verstehen 'const auto _this = this;'. Kann ich es auch in [diesem einfacheren Beispiel] (https://stackoverflow.com/questions/46688093) anwenden? – Julius

Verwandte Themen