var在自己的初始化器中使用 [英] var used in its own initializer

查看:298
本文介绍了var在自己的初始化器中使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码:

  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; (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 ++给出这个错误:

 在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:id的值在常量中不可用表达式
const auto factory = std :: get< std :: integral_constant< std :: size_t,id> {}>(_ factories).second;
^〜
src / core / include / connectionpool.h:27:41:note:在其自己的初始化程序中使用的id
constexpr const std :: size_t id {findFactoryId(_factories,名称)};
^〜
src / core / include / connectionpool.h:28:81:erreur:常量表达式中不能使用id的值
const auto factory = std :: get< std :: integral_constant< std :: size_t,id> {}>(_ factories).second;
^
src / core / include / connectionpool.h:27:41:note:在其自己的初始化程序中使用的id
constexpr const std :: size_t id {findFactoryId(_factories,name )};
^〜
src / core / include / connectionpool.h:28:81:注意:在类型为«unsigned int»的模板参数中,
const auto factory = std :: get

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

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

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

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



一个最简单的工作示例可在此处

从我所了解的 gcc 错误信息,我不应该有任何错误: id 不用于自我初始化。



这段代码是否会产生错误?



如果它应该提出一个错误,我能做些什么来解决这个错误?



谢谢你的回答。

完整的代码:

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

模板< 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) >());
}


模板< 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)...};
}

模板< typename ...连接器>
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();

$ b private:
struct foo {
constexpr foo(std :: size_t& i,const std :: string& name):i(i ),名称(名称){}
模板< class T>
constexpr void operator()(const std :: size_t is,const T pair){
i = name == pair.first?是:我;
}
std :: size_t& i;
const std :: string& name;
};

模板< 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));
返回i;
}

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


int main()
{
return 0;
}

编辑

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



编辑2



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

解决方案

问题出在这一行上:

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

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


N4296 [expr.const]¶ 2



条件表达式 e ...会评估 e 是一个核心常量表达式以下表达式之一:




  • this ,除了 constexpr 函数或 c> constexpr 构造函数,它被评估为 e 的一部分。





    令人惊讶的是,两种编译器都是如果我们简单地使用明确的这个

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

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

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


    The following code :

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

    compile with clang++, but with g++ gives this error:

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

    I'm using those command to compile:

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

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

    The only link that look like to correspond to my issue is a bug report for gcc4.9 (which is solved) : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59937.

    A minimal working example is available here.

    From what I've understood of gcc error message, I should not have any error: id isn't used to initialise itself.

    Should this code yield an error or not ?

    If it should raise an error, what could I do to solve the error ?

    Thank you for your answers.

    The complete 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

    Change link to minimal working example: a function was missing.

    EDIT 2

    Add minimal working example in the post

    解决方案

    The problem is on this line:

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

    The initializer of a constexpr variable must be a constant expression. In a constant expression you can not use the this pointer. You are implicitly using the this pointer by referring to _factories, which is a data member.

    N4296 [expr.const] ¶2

    A conditional-expression e 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;
    • ...

    Surprisingly, both compilers are happy if we simply use an explicit this:

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

    But I do not believe that is conformant. Here is a portable workaround:

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

    这篇关于var在自己的初始化器中使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆