2016-08-24 4 views
3

Мой компилятор не поддерживает if constexpr, но я очарован его выгодой.
У меня должно быть это - даже это может быть подделка.mimic "if constexpr" поведение, невозможно?

Этот код является моей попыткой имитировать поведение if constexpr.
Цель состоит в том, чтобы сделать линии (###) появляются только 1 функции: -

#include <iostream> 
using namespace std; 

template<bool Flag,typename F> constexpr typename std::enable_if<!Flag, void>::type iter_(F f,int i1){ 
    f(i1); //No! The compiler still tried to compile even Flag=true 
} 
template<bool Flag,typename F> constexpr typename std::enable_if<Flag, void>::type iter_(F f,int i1){ } 
template<bool Flag,typename F> constexpr typename std::enable_if<Flag, void>::type iter_(F f,int i1,int i2){ 
    f(i1,i2); //No! The compiler still tried to compile even Flag=false 
} 
template<bool Flag,typename F> constexpr typename std::enable_if<!Flag, void>::type iter_(F f,int i1,int i2){} 

template<bool Flag,typename F> constexpr void fff( F f ){ 
    for(int n=0;n<5;n++){//fake loop, the real situation is very complex 
     //### some horror code appeared here, but omitted 
     if(Flag){//attempt to mimic "if constexpr" 
      iter_<true>(f,1,2); 
     }else{ 
      iter_<false>(f,3); 
     } 
    } 
} 

Это его использование: -

template<typename F> constexpr void fff1( F f ){fff<false>(f);} //usage 
template<typename F> constexpr void fff2( F f ){fff<true>(f);} //usage 

int main() { 
    // your code goes here 
    auto f1=[&](int a){ 
     cout<<a<<" "; 
    }; 
    auto f2=[&](int a,int b){ 
     cout<<a<<" "<<b<<endl; 
    }; 
    fff1(f1); 
    fff2(f2); 
    return 0; 
} 

Я получил ошибка компиляции:

prog.cpp: In instantiation of 'constexpr typename std::enable_if<Flag, void>::type iter_(F, int, int) [with bool Flag = true; F = main()::<lambda(int)>; typename std::enable_if<Flag, void>::type = void]': 
prog.cpp:16:18: required from 'constexpr void fff(F) [with bool Flag = false; F = main()::<lambda(int)>]' 
prog.cpp:22:61: required from 'constexpr void fff1(F) [with F = main()::<lambda(int)>]' 
prog.cpp:33:9: required from here 
prog.cpp:9:3: error: no match for call to '(main()::<lambda(int)>) (int&, int&)' 
    f(i1,i2); 
^
prog.cpp:9:3: note: candidate: void (*)(int) <conversion> 
prog.cpp:9:3: note: candidate expects 2 arguments, 3 provided 

Из-за ошибки мне ясно, что даже если функция имеет std :: enable_if [ FALSE],
компилятор все еще скомпилировал код, который находится внутри функции. - Это плохо.

Какие части необходимо отредактировать?
... или есть альтернативы?
... или вообще невозможно подражать if constexpr (именно по этой причине оно введено окончательно)?

+1

Да, весь код внутри шаблона должен быть действительным. Таким образом, нет никакого способа иметь 'if', у которого есть ветвь, которая недействительна для шаблона и все еще сможет создать экземпляр для этого шаблона. – bolov

+1

Что вы думаете о 'if constexpr'? Нет такой вещи в C++ 11 ... – rubenvb

+1

@rubenvb, если constexpr будет в C++ 17 – Eugene

ответ

3

Прочитайте это: http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html

Мы не можем сделать это с помощью существующих возможностей языка?

Джон Спайсер предложил в C++ станд-доб-17099, что полиморфные лямбды в сочетании с шаблоном принятия решений обеспечат адекватную объекта без необходимости добавления новых возможностей языка. Вызов этого шаблона принятия решений выглядит примерно так:

template <int arg, typename ... Args> int do_something(Args... args) { 
    return static_if<sizeof...(args)>::get(
     [](auto x, auto y) { return x+y; }, 
     [](auto x) { return *x; })(args...); 
} 

Теперь, по сравнению с предлагаемым языком объекта, мы делаем

template <int arg, typename ... Args> int do_something(Args... args) { 
    constexpr if (sizeof...(args)) { 
     return (args + ...); 
    } constexpr_else { 
     return *args...; 
    } 
} 

Теперь это своего рода ап альтернатива. Это становится более сложным, если разные ветви возвращают разные типы.

Кроме того,

я должен указать на некоторые вещи здесь:

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

  • Хотя я большой сторонник использования лямбды для создания новых объектов управления, я считаю, constexpr, если решение бесконечно более читаемыми.

Далее

Ричард Смит объяснил следующее:

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

Это конкретизация общих лямбды тел фактически необходимой для нашей семантики языка - вычисления захватов общего лямбда в шаблоне функции специализации зависит от нас, уже экземпляра полного закрытия типа и его шаблон оператора вызова до такой степени, что мы знаем, где odr-использование находится в пределах независящих полных выражений внутри тела.

Напротив, целью constexpr является то, что ветвь не принята не создается.

+0

Обратите внимание, что у Boost.Hana есть такая функция: ['hana :: if_'] (https://boostorg.github.io/hana/#tutorial-integral-branching). Что касается создания экземпляра, он не создает экземпляры незакрепленных ветвей, если они являются общими лямбдами. Основываясь на комментарии Ричарда, за этим, вероятно, есть еще кое-что. – chris

Смежные вопросы