简体   繁体   English

在C ++ 11中使用auto和decltype

[英]Using auto and decltype in C++11

I'm trying to learn the currently accepted features of c++11 and I'm having trouble with auto and decltype. 我正在尝试学习当前接受的c ++ 11功能,而我遇到了auto和decltype的问题。 As a learning exercise I'm extending the std class list with some generic functions. 作为一个学习练习,我正在使用一些通用函数扩展std类列表。

template<class _Ty, class _Ax = allocator<_Ty>>
class FList : public std::list<_Ty, _Ax>
{
public:
    void iter(const function<void (_Ty)>& f)
    {
        for_each(begin(), end(), f);
    }

    auto map(const function<float (_Ty)>& f) -> FList<float>*
    {
        auto temp = new FList<float>();

        for (auto i = begin(); i != end(); i++)
            temp->push_back(f(*i));

        return temp;
    }
};

auto *ints = new FList<int>();
ints->push_back(2);
ints->iter([](int i) { cout << i; });

auto *floats = ints->map([](int i) { return (float)i; });
floats->iter([](float i) { cout << i; });

For the member map I want the return type to be generic depending on what the passed function returns. 对于成员映射,我希望返回类型是通用的,具体取决于传递的函数返回的内容。 So for the return type I could do something like this. 所以对于返回类型,我可以做这样的事情。

auto map(const function<float (_Ty)>& f) -> FList<decltype(f(_Ty))>*

This would also need to remove the float type in the function template. 这还需要删除函数模板中的float类型。

auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>*

I could use a template class but that makes the use of instances more verbose since i have to specify the return type. 我可以使用模板类,但这使得实例的使用更加冗长,因为我必须指定返回类型。

template<class T> FList<T>* map(const function<T (_Ty)>& f)

To sum of my question i'm trying to figure out how to define map without using a template class and still have it generic in the type it returns. 总结我的问题,我试图弄清楚如何在不使用模板类的情况下定义地图,并且仍然在它返回的类型中使用它。

Deriving from std::list or other std:: containers is discouraged. 不鼓励从std::list或其他std:: containers派生。

Write your operations as free functions so they can work on any standard container via iterators. 将您的操作编写为自由函数,以便它们可以通过迭代器在任何标准容器上工作。

Do you mean "define map without using a template function"? 你的意思是“不使用模板功能定义地图”?

You should be able to use the result_type member type of std::function to get the type it returns. 您应该能够使用std::functionresult_type成员类型来获取它返回的类型。

Also it's not necessary for you to specify that the function is passed as a std::function . 此外,您无需指定该函数作为std::function传递。 You could leave it open as any type, and let the compiler join everything up. 您可以将其保持为任何类型,并让编译器加入所有类型。 You only need std::function for runtime polymorphism. 您只需要std::function用于运行时多态性。

And using new to create raw heap-allocation objects and returning them by pointer is soooo 1992! 使用new创建原始堆分配对象并通过指针返回它们是soooo 1992! :) :)

Your iter function is essentially the same thing as the range-based for loop . 你的iter函数与基于范围的for循环基本相同。

But all that aside... do you mean something like this? 但除此之外......你的意思是这样吗?

template <class TFunc>
auto map(const TFunc &f) -> FList<decltype(f(_Ty()))>*
{
    auto temp = new FList<decltype(f(_Ty()))>();

    for (auto i = begin(); i != end(); i++)
        temp->push_back(f(*i));

    return temp;
}

This will match anything callable, and will figure out the return type of the function by using decltype. 这将匹配任何可调用的东西,并将使用decltype找出函数的返回类型。

Note that it requires _Ty to be default constructable. 请注意,它要求_Ty是默认构造的。 You can get around that by manufacturing an instance: 您可以通过制造实例来解决这个问题:

template <class T>
T make_instance();

No implementation is required because no code is generated that calls it, so the linker has nothing to complain about (thanks to dribeas for pointing this out!) 不需要实现,因为没有生成调用它的代码,因此链接器没有什么可抱怨的(感谢dribeas指出这个!)

So the code now becomes: 所以代码现在变成:

FList<decltype(f(make_instance<_Ty>()))>*

Or, literally, a list of whatever the type would be you'd get from calling the function f with a reference to an instance of _Ty. 或者,字面上,您可以通过引用_Ty实例调用函数f获得的类型列表。

And as a free bonus for accepting, look up rvalue references - these will mean that you can write: 并且作为接受的免费奖励,查找右值引用 - 这意味着您可以写:

std::list<C> make_list_somehow()
{
    std::list<C> result;
    // blah...
    return result;
}

And then call it like this: 然后像这样调用它:

std::list<C> l(make_list_somehow());

Because std::list will have a "move constructor" (like a copy constructor but chosen when the argument is a temporary, like here), it can steal the contents of the return value, ie do the same as an optimal swap . 因为std :: list将有一个“移动构造函数”(就像复制构造函数一样,但是当参数是临时的时候选择,就像这里一样),它可以窃取返回值的内容,即与最佳swap相同。 So there's no copying of the whole list. 所以没有复制整个列表。 (This is why C++0x will make naively-written existing code run faster - many popular but ugly performance tricks will become obsolete). (这就是为什么C ++ 0x会使天真编写的现有代码运行得更快 - 许多流行但丑陋的性能技巧将变得过时)。

And you can get the same kind of thing for free for ANY existing class of your own, without having to write a correct move constructor, by using unique_ptr . 而且你可以通过使用unique_ptr免费为你自己的任何现有类获得相同类型的东西,而无需编写正确的移动构造函数。

std::unique_ptr<MyThing> myThing(make_my_thing_somehow());

You can't use auto in function arguments where you want the types of the arguments to be deduced. 您不能在函数参数中使用auto,因为您希望推导出参数的类型。 You use templates for that. 你使用模板。 Have a look at: http://thenewcpp.wordpress.com/2011/10/18/the-keyword-auto/ and http://thenewcpp.wordpress.com/2011/10/25/decltype-and-declval/ . 看看: http//thenewcpp.wordpress.com/2011/10/18/the-keyword-auto/http://thenewcpp.wordpress.com/2011/10/25/decltype-and-declval/ They both explain how to use auto and decltype. 他们都解释了如何使用auto和decltype。 They should give you enough information about how they are used. 他们应该为您提供有关如何使用它们的足够信息。 In particular, another answer about make_instance could be done better with declval. 特别是,关于make_instance的另一个答案可以通过declval更好地完成。

I think the point that Jarrah was making in his answer is that those points do explain exactly how to use these things. 我认为Jarrah在他的回答中提出的观点是,这些要点确实解释了如何使用这些东西。 I will point out the details anyway: 无论如何我会指出细节:

You can't do this, there are two things wrong: 你不能这样做,有两件事是错的:

auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>*

auto can't be used for function arguments. auto不能用于函数参数。 If you want the type of the function to be deduced then you should use templates. 如果您想要推导出函数的类型,那么您应该使用模板。 The second is that decltype takes an expression, whereas _Ty is a type. 第二个是decltype采用表达式,而_Ty是一个类型。 Here is how to solve it: 以下是如何解决它:

template <typename Ret>
auto
map(const function<Ret (_Ty)>& f)
  -> FList<decltype(f(declval<_Ty>()))>
{}

That way there is no magic to create an instance of a type. 这样,创建一个类型的实例就没有魔力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM