2016-03-22 1 views
0

Рассмотрим этот шаблонКак обеспечить, чтобы тип функции, переданный как аргумент шаблона, не изменял аргументы?

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

Я хочу, чтобы убедиться, что function не мутировать bar. Не следует компилировать следующее.

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

Однако обе эти строки должны быть скомпилированы.

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

Какие методы могут быть использованы? Упрощение лучше, но я бы предпочел интроспекцию типа шаблона над std::function или сигнатурой указателя функции.

ответ

2

С SFINAE, вы можете сделать:

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

Это хорошая альтернатива, если вы хотите, чтобы требование было максимально приближенным к объявлению функции, а не похоронить его в реализации, где оно может потеряться или случайно удалено. – Mankarse

3

Вы можете изменить foo вызвать function с версией const из bar:

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

Для C++ 11, это нормально. Перед C++ 11 необходимы 'Bar const & c_bar' или' const Bar & c_bar = bar'. Не все могут перейти на C++ 11. – Peter

+0

@Peter question.has 'C++ 11' tag –

+0

Я знаю, Револьвер. Он также имеет тег C++. C++ и C++ 11 не являются синонимами. – Peter

0

Только после публикации я понял, что я мог бы сделать следующее

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 ,

3

Самый простой метод должен был бы использовать функцию as_const утилиты (с C++ 17):

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

Вы могли бы быть четко о вашем типе.

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

Это не сработает, если лямбда зафиксировала любые переменные (поскольку неявное преобразование в указатель функции будет отключено). – Mankarse

+0

@ Mankarse А, я об этом не думал. – Johannes