如何确保作为模板参数传递的函数类型不修改参数?

How to ensure that function type passed as template argument does not modify arguments?

考虑这个模板

template<typename FunctionType>
void foo(FunctionType && function)
{
  Bar b;
  bar.mutateState();
  function(bar);
}

我想确保 function 不会变异 bar。以下不应该编译。

foo([](Bar &){});

但是,这两行都应该编译。

foo([](const Bar &){});
foo([](Bar){});

可以使用哪些技巧?越简单越好,但我更喜欢模板类型自省而不是 std::function 或函数指针签名。

您可以修改 foo 以使用 barconst 版本调用 function

template<typename FunctionType>
void foo(FunctionType && function)
{
  Bar bar;
  bar.mutateState();
  auto const & c_bar = bar;
  function(c_bar);
}

发帖后我意识到我可以做以下事情

template<typename T>
typename std::add_const<T>::type &asConst(T &t)
{
    return t;
}

template<typename FunctionType>
void Foo(FunctionType && function)
{
  Bar bar;
  bar.mutateState();
  function(asConst(bar));
}

显然这包含在 C++17 中作为 std::as_const

最简单的方法是使用as_const效用函数(C++17 起):

template<typename FunctionType>
void foo(FunctionType && function)
{
  Bar b;
  bar.mutateState();
  function(std::as_const(bar));
}

你可以明确说明你的类型。

#pragma once

class Bar
{
    int a;
public:
    Bar() : a{0}
    {}
    void mutateState()
    {
        ++a;
    }
};

void foo(void(*function)(const Bar &))
{
    Bar bar;
    bar.mutateState();
    function(bar);
}

int main()
{
    foo([](const Bar &)
    {});
    foo([](Bar)
    {});
}

使用 SFINAE,您可以:

template<typename FunctionType>
auto foo(FunctionType && function)
-> decltype(function(std::declval<const Bar&>()), void())
{
  Bar bar;
  bar.mutateState();
  function(bar);
}