C вычисляет выражение, которого не должно быть

#c #operator-overloading

#c #перегрузка оператора

Вопрос:

Я переопределил operator| действовать как фильтр для заданного vector и функции, если эта функция возвращает a bool . В случае, если этого не происходит, он вызывает for_each vector .

 template<typename T, typename Func>
auto operator | (const vector<T> amp;v, Func f){
  bool result = is_same<bool, decltype(f(v[0]))>::value;
  vector<T> temp;
  if (result){
    temp.reserve(v.size());
    for(auto itr = v.begin(); itr != v.end();   itr){
      bool func_return = f(*itr);
      if (func_return){
        temp.push_back(*itr);
      }
    }
    return temp;
  }
  else{
    for_each(v.begin(),v.end(),f);
    return temp;
  }
}
  

Этот код отлично работает, когда действует как фильтр, но for_each часть не работает. Всякий раз, когда я пытаюсь запустить следующий код:

 int main() {
vector<int> v1 = { 2, 9, 8, 8, 7, 4 };
v1 | []( int x ) { return x % 2 == 0; } | [] ( int x ) { cout << x << " "; };
}
  

Компилятор возвращает:

 error: cannot initialize a variable of type 'bool' with an rvalue of type 'void'
bool func_return = f(*itr);

in instantiation of function template
      specialization 'operator|<int, (lambda at
      main.cpp:44:43)>' requested here
v1 | []( int x ) { return x % 2 == 0; } | [] ( int x ) { cou...
                                        ^
  

Что кажется мне странным, в конце концов, компилятор не должен выполнять эту строку во втором операторе, как result и должно быть false . Кто-нибудь может мне помочь в этом?

Комментарии:

1. Компилятор компилирует ветви if и else. Вы должны использовать if constexpr и C 17.

2. if constexpr возникнет проблема, которая v[0] не известна во время компиляции. Какой способ проверить во время компиляции, что Func это за функция, которая принимает a T в качестве аргумента и возвращает a bool ? Какое-то сравнение с an std::function ?

3. Или… Я думаю, нам на самом деле не нужно знать v[0] во время компиляции, потому что для получения decltype нам просто нужно знать тип v , подпись vector<T>::operator[] и подпись f::operator() , которые все известны во время компиляции. Значит ли это, что оно работает даже с пустым вектором?

4. @NathanPierson Да, с пустым вектором проблем нет. v[42] было бы то же самое, v[0] что и внутри decltype .

Ответ №1:

Это лямбда:

 [] ( int x ) { cout << x << " "; }
  

имеет void возвращаемый тип, поэтому эта строка:

 bool func_return = f(*itr);
  

не компилируется. Поскольку значение result зависит только от Func и T , у вас есть необходимая информация, чтобы решить, выполнять ли if ветку во время компиляции. Вы можете использовать a constexpr if вместо времени выполнения if :

 if constexpr(result)
  

и теперь код внутри этой ветви не будет скомпилирован, когда функция создается с неправильными типами.

Кроме того, вам нужно сделать result время компиляции постоянным, чтобы использовать его в if constexpr условии.

Вот демонстрация.