简体   繁体   English

基于后面模板类型的默认模板类型

[英]Default template type based on later template type

I have a function which creates an object and inserts it into a container.我有一个 function ,它创建一个 object 并将其插入容器中。 In most cases, the object type is the same as that of the container elements.在大多数情况下,object 类型与容器元素的类型相同。 Then, I don't want to have to specify the object type.然后,我不想指定 object 类型。 But for containers holding std::variant , I want to be able to specify the object type as the first template parameter.但是对于持有std::variant的容器,我希望能够将 object 类型指定为第一个模板参数。 Here's the non-working example:这是非工作示例:

template<typename T>
using remove_qualifiers = std::remove_cv_t<std::remove_reference_t<T>>;
template<typename T>
using IteratorType = decltype( std::declval<remove_qualifiers<T>>().end() );
template<typename T>
using ElementType = decltype( *( std::declval<remove_qualifiers<T>>().end() ) );

template<typename E = ElementType<T>, typename T, typename ... Args>
IteratorType<T> insert( T& someContainer, Args&& ... ){
    IteratorType<T> it { someFindFunc() };
    return someContainer.insert(it, E{std::forward<Args>(args) ...});
}

The problem is, that the default type for E is based on T , which at this point is not declared yet.问题是, E的默认类型基于T ,此时尚未声明。 But if I change the order, then calling the function becomes awkward.但是如果我更改顺序,那么调用 function 就会变得很尴尬。

How can I make this pattern work, so that I can call the function both with and without specifying E ?如何使这种模式起作用,以便我可以在指定和不指定E的情况下调用 function ?

I guess this is likely a case of not finding the right search terms.我想这可能是没有找到正确的搜索词的情况。 I looked at this , this , this , and this one, and they don't appear to be what I'm looking for.我看了这个这个这个这个,它们似乎不是我要找的。

Consider wrap it into a class template so that you don't need to worry about specifying the type of the container.考虑将其包装到 class 模板中,这样您就不必担心指定容器的类型。

template <typename T>
class Inserter {
public:
    Inserter(T& someContainer): container{someContainer} {}
    using IteratorType = decltype( std::declval<remove_qualifiers<T>>().end() );

    template <typename E = ElementType<T>, typename... Args>
    IteratorType insert(Args&&... args) {
        IteratorType it = container.begin(); // just for sample
        return container.insert(it, E{std::forward<Args>(args) ...});
    }
private:
    T& container;
};

Then,然后,

std::vector<std::variant<int, double>> v;
Inserter{v}.insert<int>(1);
Inserter{v}.insert<double>(1.1);

Demo演示

If you are not using some sort of emplace, you should just move construction to the caller.如果您不使用某种 emplace,则应该将构造移至调用者。 For simplicity I'm using push_back instead of insert .为简单起见,我使用push_back而不是insert

template <typename T, typename Value>
inline auto insert(T& container, Value&& value) {
  container.push_back(std::forward<Value>(value));
}

But let's assume you are really constructing the type in place.但是让我们假设您确实在适当地构造类型。

template <typename T, typename... Args>
inline auto emplace(T& container, Args&&... args) {
  container.emplace_back(std::forward<Args>(args)...);
}

This is possibly all you need.这可能就是您所需要的。 You can construct any type, variants as well.您也可以构造任何类型、变体。

struct A {  int n; };
struct B {  int n; };

auto a = std::vector<A>{};
emplace(a, 100);

auto b = std::vector<B>{};
emplace(b, 100);

auto ab = std::vector<std::variant<A, B>>{};
emplace(ab, std::in_place_type_t<A>{}, 100); // tell the type
emplace(ab, 100); // ambigious, compile error

As for your specific use-case, there is no way of deducing some sort of default type of a variant.至于您的特定用例,无法推断出某种默认类型的变体。 You always have to tell explicitly what to construct.你总是必须明确地告诉你要构造什么。

You can reinvent the wheel, create an overload for variants and then hide std::in_place_type_t .您可以重新发明轮子,为变体创建重载,然后隐藏std::in_place_type_t But generally this problem has been solved by the STL for any type that can be constructed in place.但通常这个问题已经被 STL 解决了,对于任何可以就地构建的类型。

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

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