var在其自己的初始值设定项

时间:2017-05-02 19:15:00

标签: c++ templates gcc clang

以下代码:

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

使用clang ++进行编译,但使用g ++会出现此错误:

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

我正在使用这些命令编译:

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

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

与我的问题相对应的唯一链接是gcc4.9的错误报告(已解决):https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59937

可以使用最小的工作示例here

根据我对gcc错误消息的理解,我不会有任何错误:id不会用于初始化。

此代码是否会产生错误?

如果它应该引发错误,我该怎么做才能解决错误?

感谢您的回答。

完整的代码:

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

修改

将链接更改为最小工作示例:缺少某个功能。

编辑2

在帖子中添加最小的工作示例

1 个答案:

答案 0 :(得分:4)

问题在于这一行:

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

constexpr变量的初始值设定项必须是常量表达式。在常量表达式中,您不能使用this指针。您通过引用this隐式使用_factories指针,e是数据成员。

  

N4296 [expr.const]¶2

     

条件表达式 e核心常量表达式,除非评估this ...将评估以下表达式之一:

     
      
  • constexprconstexpr函数或e构造函数除外,this正在评估;
  •   
  • ...
  •   

令人惊讶的是,如果我们只使用明确的constexpr const std::size_t id{findFactoryId(this->_factories, name)};

,两个编译器都很高兴
const auto _this = this;
constexpr const std::size_t id{findFactoryId(_this->_factories, name)};

但我不相信这是符合的。这是一个便携式解决方法:

for i in ...