关于 Lambda函数和表达式的wikipedia文章:
用户通常希望在该位置附近定义谓词函数 他们在哪里进行算法函数调用。语言只有一个 这个机制:在一个内部定义一个类的能力 功能。 ...函数中定义的类不允许在模板中使用
这是否意味着在C ++ 0x lambda到位后,在函数内使用嵌套结构会被默默地弃用?
另外,上一段中最后一行的含义是什么?我知道嵌套类不能是template
;但那条线并不意味着。
答案 0 :(得分:8)
我不确定我理解你的困惑,但我会陈述所有事实并让你解决它。 :)
在C ++ 03中,这是合法的:
#include <iostream>
int main()
{
struct func
{
void operator()(int x) const
{
std::cout << x << std::endl;
}
};
func f; // okay
f(-1); // okay
for (std::size_t i = 0; i < 10; ++i)
f(i) ; // okay
}
但如果我们尝试这样做,那就不是:
template <typename Func>
void exec(Func f)
{
f(1337);
}
int main()
{
// ...
exec(func); // not okay, local classes not usable as template argument
}
这给我们留下了一个问题:我们想要定义用于此函数的谓词,但我们不能将放在函数中。所以我们不得不把它移到任何外围的范围并在那里使用它。这些杂乱的东西不仅没有其他人需要知道的东西,而且它使谓词远离它的使用位置,使得阅读代码变得更加困难。
对于函数中偶尔重用的代码块,它仍然可能有用(例如,在上面的循环中;你可以通过其参数将函数谓词添加到某个复杂的东西中),但大部分时间我们都想在模板中使用它们。
C ++ 0x更改规则以允许上述代码工作。他们还添加了lambdas:用于将函数对象创建为表达式的语法,如下所示:
int main()
{
// same function as above, more succinct
auto func = [](int x){ std::cout << x << std::endl; };
// ...
}
这与上面完全相同,但更简单。那么我们还有什么用于“真正的”本地课程吗?当然。毕竟Lambda没有完整的功能:
#include <iostream>
template <typename Func>
void exec(Func func)
{
func(1337);
}
int main()
{
struct func
{
// note: not possible in C++0x lambdas
void operator()(const char* str) const
{
std::cout << str << std::endl;
}
void operator()(int val) const
{
std::cout << val << std::endl;
}
};
func f; // okay
f("a string, ints next"); // okay
for (std::size_t i = 0; i < 10; ++i)
f(i) ; // okay
exec(f); // okay
}
也就是说,对于lambda来说,你可能不会比以前更多地看到本地课程,但出于完全不同的原因:一个几乎无用,另一个几乎被取代。
答案 1 :(得分:3)
定义函数内部的结构从来都不是处理缺少谓词的一种特别好的方法。它有效,如果你有一个虚拟基础,但它仍然是一个非常丑陋的方式来处理事情。它可能看起来像这样:
struct virtual_base {
virtual void operator()() = 0;
};
void foo() {
struct impl : public virtual_base {
void operator()() { /* ... */ }
};
register_callback(new impl);
}
如果你想要的话,你仍然可以继续使用这些类 - 内部函数 - 它们不会被弃用或瘫痪;他们从一开始就受到限制。例如,在C ++ 0x之前的C ++版本中,此代码是非法的:
void foo() {
struct x { /* ... */ };
std::vector<x> y; // illegal; x is a class defined in a function
boost::function<void()> z = x(); // illegal; x is used to instantiate a templated constructor of boost::function
}
这种用法在C ++ 0x中实际上是合法的,所以如果有的话,内部类的实用性实际上已经扩展了。尽管如此,它仍然不是一种很好的做事方式。
答案 2 :(得分:3)
引入lambda后,函数内部是否有任何用例?
当然。在函数内部有一个类是:
显然有一个阈值,在函数内部有一个大类会损害可读性并混淆函数本身的流程 - 对于大多数开发人员和情况来说,阈值非常低。对于一个大类,即使只有一个函数可以使用它,将两者放入一个单独的源文件可能更清晰。但是,这只是调整品味。
您可以将此视为在类中具有私有函数的反转:在这种情况下,外部API是类的公共接口,函数保持私有。在这种情况下,该函数使用一个类作为私有实现细节,后者也保持私有。 C ++是一种多范式语言,适当地为程序组织和API暴露的层次结构建模提供了这种灵活性。
示例:
float
或double
来访问mantisa / exponent / sign,并在内部决定使用{{来模拟该值为方便起见,使用合适宽度的位域(注意:实现定义的行为)函数中定义的类不允许在模板中使用它们
我认为你评论说别人的答案已经解释了这一点,但无论如何......
struct
答案 3 :(得分:2)
Boost.Variant。
Lambdas不适用于变体,因为变体需要具有多个operator()(或具有模板化运算符())的对象。
0x允许现在在模板中使用本地类,因此boost::apply_variant
可以使用它们。
答案 4 :(得分:2)
正如Tony所提到的,函数内部的一个类不仅仅是谓词。除了其他用例之外,它还允许创建一个工厂函数,该函数创建确认接口的对象,而不暴露实现类。见这个例子:
#include <iostream>
/* I think i found this "trick" in [Alexandrescu, Modern C++ Design] */
class MyInterface {
public:
virtual void doSomethingUseful() = 0;
};
MyInterface* factory() {
class HiddenImplementation : public MyInterface {
void doSomethingUseful () {
std::cout << "Hello, World!" << std::endl;
}
};
return new HiddenImplementation();
}
int main () {
auto someInstance = factory();
someInstance->doSomethingUseful();
}