简体   繁体   English

decltype不推导const对象的const成员

[英]decltype does not deduce const members for const objects

#include <type_traits>
#include <functional>

struct Chains
{};

struct Stages
{

    Chains mutating_chains;

    Chains sideffect_chains;

    Chains write_chains;

    void forall_chains(const std::function<void(Chains & chain)> & fun)
    {
        forall_chains(*this, fun);
    }

    void forall_chains(
        const std::function<void(const Chains & chain)> & fun) const
    {
        forall_chains(*this, fun);
    }

    template <typename Self>
    static void forall_chains(
        Self & self,
        const std::function<void(decltype(self.mutating_chains) & chain)> & fun)
    {
        fun(self.mutating_chains);
        fun(self.sideffect_chains);
        fun(self.write_chains);
    }
};

There is obviously something that I can't understand with decltype . 显然有一些我无法用decltype理解的东西。 Because according to the error message that the compiler throws, Self is deduced as const Stages, so Why self.member is not deduced as const member? 因为根据编译器抛出的错误消息,Self被推断为const阶段,那么为什么self.member不推导为const成员? Also how to make it work correctly, deduce const members for const objects? 另外如何使它正常工作,演绎const对象的const成员? I added parenthesis to the expression decltype((self.mutating_chains)) and that passed compilation but I'm not sure if that is the correct thing to do. 我在表达式decltype((self.mutating_chains))添加了括号,并且通过了编译,但我不确定这是否正确。

f.cpp: In instantiation of ‘static void Stages::forall_chains(Self&, const std::function<void(decltype (self.mutating_chains)&)>&) [with Self = const Stages; decltype (self.mutating_chains) = Chains]’:
f.cpp:150:33:   required from here
f.cpp:158:33: error: no match for call to ‘(const std::function<void(Chains&)>) (const Chains&)’
         fun(self.mutating_chains);

I added parenthesis to the expression decltype((self.mutating_chains)) and that passed compilation but I'm not sure if that is the correct thing to do. 我在表达式decltype((self.mutating_chains))添加了括号,并且通过了编译,但我不确定这是否正确。

Yes, that is the correct thing to do in this case. 是的,在这种情况下,这是正确的做法。 In short, decltype(x) gives you the declared type of x , which does not depend on the value category of the expression. 简而言之, decltype(x)为您提供声明x 类型 ,它不依赖于表达式的值类别。

For an lvalue expression x of type T , decltype((x)) instead yields T& , which in your case gets the const qualifier applied correctly. 对于类型为T左值表达式 xdecltype((x))代替产生T& ,在您的情况下,正确地应用了const限定符。

You can find a more formal (and accurate) explanation on the cppreference page for decltype(...) . 您可以在decltype(...)cppreference页面上找到更正式(和准确)的解释。


By the way, please consider passing your callback via a template argument instead of std::function . 顺便说一句,请考虑通过模板参数而不是std::function传递回调。 The latter is not a zero-cost abstraction - it's a heavyweight wrapper that uses type erasure whose usage should be minimized. 后者不是零成本抽象 - 它是一个使用类型擦除的重量级包装器,其使用应该最小化。

template <typename Self, typename F>
static void forall_chains(Self& self,  F&& fun){ /* ... */ }

I wrote an article about the subject: passing functions to functions . 我写了一篇关于这个主题的文章: 将函数传递给函数

Yes, indeed. 确实是的。 decltype has a special case for decltype(self.mutating_chains) (emphasis mine): decltype有一个特殊的decltype(self.mutating_chains)案例decltype(self.mutating_chains) (强调我的):

If the argument is an unparenthesized id-expression or an unparenthesized class member access expression , then decltype yields the type of the entity named by this expression. 如果参数是未加密码的id-expression或未加括号的类成员访问表达式 ,则decltype将生成此表达式命名的实体的类型。

So you get the actual type with which self.mutating_chains has been declared, that is Chains . 因此,您将获得已声明self.mutating_chains的实际类型,即Chains

When you add parentheses, you fall back into the general case, which actually evaluates the type of the expression, which in the case of a const Self is const Chains & as expected: 当你添加括号时,你会回到一般情况,它实际上会计算表达式的类型,在const Self的情况下,它是const Chains &预期的:

If the argument is any other expression of type T , and 如果参数是T类型的任何其他表达式,则
a) [...] 一种) [...]
b) if the value category of expression is lvalue, then decltype yields T& ; b)如果表达式的值类别是左值,则decltype产生T& ;
c) [...] C) [...]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM