私有编译时 -> 运行 时间适配器。奇怪的编译错误

Private compile-time -> run-time adapter. Strange compilation error

基本上,此代码失败并出现一个非常奇怪的错误:

<source>:75:29: error: cannot convert 'get_view<main()::<unnamed struct>, run_time::data_view>::operator()(const main()::<unnamed struct>&) const::View::code' from type 'int (get_view<main()::<unnamed struct>, run_time::data_view>::operator()(const main()::<unnamed struct>&) const::View::)() const' to type 'int'
   75 |                 return data.code;

https://godbolt.org/z/T3h1a7zne

template <typename SourceT, typename ViewT>
struct get_view;

template <typename SourceT>
struct get_view<SourceT, SourceT>
{
    constexpr decltype(auto) operator()(const SourceT &source) const
    {
        return source;
    }
};

// api.h 

#include <iostream>

class compile_time
{
public:

  template <typename DataT>
  void operator()(const DataT &data) const
  {
      std::cout << "compile-time: " << data.code << std::endl;
  }
};

class run_time
{
    // How to make data_view private?
// private:
public:
    class data_view; 

public:

  template <typename DataT>
  void operator()(const DataT &data) const
  {
      (*this)(get_view<DataT, data_view>{}(data));
  }

private:
  void operator()(const data_view &data) const;
};

class run_time::data_view
{
public:

  virtual int code() const = 0;

protected:
  ~data_view() = default; // do not own this 
};


template <typename DataT>
struct get_view<DataT, run_time::data_view>
{
    // don't want to return std::unique_ptr<data_view>
    auto operator()(const DataT &data) const
    {
        struct View : run_time::data_view {
            const DataT& data;

            View(const DataT &data)
              : data(data)
            {}
            
            int code() const override
            {
                return data.code;
            }
        };

        return View(data);
    }
};


// .cpp

void run_time::operator()(const run_time::data_view &dataView) const
{
    std::cout << "run-time: " << dataView.code() << std::endl;
} 

// main.cpp

int main()
{
    struct {
        double irrelevant;
        int code;
    } data{42, 815};

    compile_time{}(data);
    run_time{}(data); // does not compile!!!

    return 0;
}

我找不到解释。 为什么说data.code是函数类型呢?

有可能使这项工作吗?我不希望 data_view 返回为 std::unique_ptr

我的期望:

那么谁能解释它失败的原因以及如何在不诉诸堆分配的情况下使其工作? (run_time::data_view 应该是私有的。我不希望它在 class 或指定适配器 get_view 之外的任何地方使用。


这有效:

  template <typename DataT>
  void operator()(const DataT &data) const
  {
      const data_view &view = get_view<DataT, data_view>{}(data);
      (*this)(view);
  }

我猜它会导致递归,因为从 get_view 推导出来的 auto 不是 const data_view& 类型。所以编译器对调用哪个 operator()(data) 感到困惑。通过显式转换为引用,它变得清晰。

但是,有一个问题是为什么它决定首先使用模板,而不是采用 const 引用的重载。

问题是由函数解析过程中的歧义引起的: get_view returns deduced 按值类型是一个很好的候选者 template <typename DataT> operator()(const DataT &),从而忽略现有的重载 operator()(const data_view &)

在运算符调用之前提供显式转换解决了问题。

  template <typename DataT>
  void operator()(const DataT &data) const
  {
      const data_view &view = get_view<DataT, data_view>{}(data);
      (*this)(view);
  }