decltype不推导const对象

时间:2017-05-05 12:30:41

标签: c++ c++11 metaprogramming

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

decltype显然有些事我无法理解。因为根据编译器抛出的错误消息,Self被推断为const阶段,那么为什么self.member不推导为const成员?另外如何使它正常工作,演绎const对象的const成员?我在表达式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);

2 个答案:

答案 0 :(得分:4)

  

我在表达式decltype((self.mutating_chains))中添加了括号并且通过了编译,但我不确定这是否正确。

是的,在这种情况下,这是正确的做法。简而言之,decltype(x)为您提供了x声明类型,它不依赖于表达式的值类别。

对于x类型的左值表达式 Tdecltype((x))会产生T&,在您的情况下会得到const }限定符应用正确。

您可以在cppreference page for decltype(...)上找到更正式(准确)的解释。

顺便提一下,请考虑通过模板参数而不是std::function传递回调。后者不是零成本抽象 - 它是一个使用类型擦除的重量级包装器,其使用应该被最小化。

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

我写了一篇关于这个主题的文章:passing functions to functions

答案 1 :(得分:4)

是的,的确如此。 decltypedecltype(self.mutating_chains)的特殊情况(强调我的):

  

如果参数是未加密码的id-expression或未加密码的类成员访问表达式,则decltype将生成此表达式命名的实体的类型。

因此,您获得已声明self.mutating_chains的实际类型,即Chains

当您添加括号时,您会回到一般情况,它实际上会评估表达式的类型,如果const Selfconst Chains &,则表达式符合预期:

  

如果参数是T类型的任何其他表达式,则为   a)[...]
  b)如果表达式的值类别是左值,则decltype产生T&;
  c)[...]