2013-04-27 98 views
3

我希望能够避免在编译时知道条件为假时调用函数。现在我用的是这样的:在编译时避免函数调用错误的情况

template<bool Enabled> 
void fun(params) 
{ 
    //do nothing 
} 

template<> 
void fun<true>(params) 
{ 
    //do something with params. 
} 

我不同意这种形式给出的喜欢的事情是,即使函数体为空时params进行评估。

我想要一个解决方案,当函数根本不被调用,并且在条件为false时不会评估参数(这可能会在第一种情况下使用空函数进行优化,但我不能假设这在每个编译器中都是如此)。

这甚至可能吗?

+1

你确定编译器没有这样做吗? – 2013-04-27 20:50:12

+0

@BoPersson如果参数评估有副作用,即使函数体是空的,也应该评估它们。在标准AFAIK中也没有规定,如果空函数是空的,则不应调用空函数(这可能由大多数编译器完成) – Felics 2013-04-27 20:56:09

+0

我相信你回答了你自己的问题。 – jrok 2013-04-27 20:58:33

回答

13

是的。

template<bool b, typename Func, typename FuncElse> 
struct compile_time_if_functor { 
    void operator()(Func&& f, FuncElse&&) const{ 
    std::forward<Func>(f)(); 
    } 
}; 
template<typename Func, typename FuncElse> 
struct compile_time_if_functor<false, Func, FuncElse> { 
    void operator()(Func&&, FuncElse&& else_f ) const{ 
    std:forward<FuncElse>(else_f)(); 
    } 
}; 
template<bool b, typename Func, typename Else> 
void compile_time_if(Func&& f, Else&& elsef) { 
    compile_time_if_functor<b, Func, Else> functor; 
    functor(
    std::forward<Func>(f), 
    std::forward<Else>(elsef) 
); 
} 
template<bool b, typename Func> 
void compile_time_if(Func&& f) { 
    auto do_nothing = []{}; 
    compile_time_if<b>(std::forward<Func>(f), std::move(do_nothing)); 
} 

使用:

int main() { 
    compile_time_if<expression>([&]{ 
    // code that runs iff expression is true 
    }); 
    compile_time_if<expression2>([&]{ 
    // code that runs iff expression2 is true 
    },[&]{ 
    // else clause, runs iff expression2 is false 
    }); 
} 

注意,{}内的代码被编译,但不运行,如果是在if错误的分支。因此,代码需要在类型级别上良好形成和合法,但在运行时执行并不一定合法。在这些lambda表达式中不能创建大小为0的数组!

一个发烧友方法可以让你无限期地链接if-else块。如果我想这样做,我会使用命名操作符技巧。

首先,更改compile_time_if返回std::integral_constant< bool, b >

然后,写compile_time_else(Func&&)compile_time_elseif<bool>(Func&&)其返回包Func并重写operator*(std::true_type, X)operator*(std::false_type, X)运行或不运行Func并返回std::true_typestd::false_type类型。

的最终目标应该是这样的语法:

If<expression>([&]{ 
    // block 1 
})*Else([&]{ 
    // block 2 
}); 

If<expression>([&]{ 
    // block 1 
})*ElseIf<expression2>([&]{ 
    // block 2 
})*ElseIf<expression3>([&]{ 
    // block 3 
})*Else([&]{ 
    // block 4 
}); 

使全级联上的流量控制。你甚至可以这么做:

compile_time_switch<value>(
    Case<c0, FallThrough>(), 
    Case<c1>([&]{ 
    // block 1 
    }), 
    Case<c2, Continue>([&]{ 
    // block 2 
    }), 
    Case<c3>([&]{ 
    // block 3 
    }), 
    Case<c4>([&]->CanContinue{ 
    // block 4 
    if (condition) { 
     return Continue; 
    } else { 
     return Break; 
    } 
    }), 
    Case<c4>([&]{ 
    }), 
    Default([&]{ 
    }) 
}; 

但那是超越自我。

有关如何以编译时允许编译器操作流控制的方式复制C++语法的想法,请查看boost phoenix。我只是为了完整而将其包括在内:实际上写这种东西并不是那么实际,因为一些可怜的草皮将不得不维持它,并且在你写这些东西的前几次你会做一份糟糕的工作!

+0

我想你应该明确指出,所有这些lambda表达式中的代码都需要格式良好,你也可以在“编译”部分提到它。 – Xeo 2013-04-27 21:09:51

+0

现在为'if(表达式){} else {};添加一些宏观魔法;(与赋值运算符一起工作);} – dyp 2013-04-27 21:54:24

+0

@DyP Bah,宏是邪恶的。 ;)'#define If(expression)compile_time_if ()= [&]'和'#define Else * compile_time_else * [&]'和#define ElseIf(expression)* compile_time_else_if * [&]'with many of template背后的样板和超载乐趣。 – Yakk 2013-04-28 02:13:02

相关问题