繁体   English   中英

嵌套类构造函数中的父模板参数推导

[英]Parent template argument deduction in nested class constructor

我正在尝试编写可以推导出父类模板的嵌套类的“promotion”构造函数。 它适用于父类,但不适用于嵌套类。 这是一个代码示例。

template <class T>
struct potato {
    struct baked {
        template <class O>
        baked(const typename potato<O>::baked& p)
                : something(static_cast<T>(p.something)) {
        }
        baked() = default;

        T something;
    };

    template <class O>
    potato(const potato<O>& p)
            : mybaked(p.mybaked) {
    }
    potato() = default;

    baked mybaked;
};

int main(int, char**) {
    potato<int> potato1;
    potato<short> potato2(potato1);
}

这合法吗?

各种编译器输出各种错误。 Clang在我的脑海中最具可读性。 它指出 :

候选模板被忽略:无法推断模板参数'O'

https://godbolt.org/z/y_IZiE

所以我猜我要么弄乱签名,要么这不是c ++支持的功能。

我不知道有什么方法可以推断出baked的母potato<T>的模板参数T 您可以使用decltype(p.something)知道T但这似乎不能帮助解决调用构造函数的问题。 一个解决方法是更改baked的构造函数以获取任何O并假设它有something

struct baked {
    template <class O>
    baked(const O & p) : something(static_cast<T>(p.something))
    { }

    baked() = default;

    T something;
};

这可以工作,但它比原始代码似乎打算更不类型安全。 这个问题的一个解决方法可能是引入一个static_assert来检查O实际上是一个potato<U>::baked

#include <type_traits>

template <class T>
struct potato {
    struct baked {
        template <class O>
        baked(const O & p) : something(static_cast<T>(p.something))
        {
            using t_parent = potato<decltype(p.something)>;
            static_assert(std::is_same<O, typename t_parent::baked>::value, "Not a baked potato!");
        }

        baked() = default;

        T something;
    };

    template <class O>
    potato(const potato<O>& p)
        : mybaked(p.mybaked) {
    }
    potato() = default;

    baked mybaked;
};

这应该编译好用于预期的用途,但失败的“不是烤土豆!” 如果你试图通过something传递任何其他something 这会失败:

struct foo {
    int something = 0;
};


int main(int, char**) {
    foo bar;
    potato<int>::baked baz(bar); // Error: Not a baked potato!
}

由于编译器O状态不能从const typename potato<O>::baked& (在::左侧)中推断出来。

您有几种解决方法:

  • 移动baked父母外部并使其成为模板:

     // Possibly in namespace details template <typename T> struct baked_impl { template <class O> baked_impl(const typename baked_impl<O>& p) : something(static_cast<T>(p.something)) { } baked_impl() = default; T something; }; template <class T> struct potato { using baked = baked_impl<T>; // ... }; 
  • baked添加父信息并使用SFINAE:

     template <class T> struct potato; // traits for SFINAE template <class T> struct is_potato : std::false_type {}; template <class T> struct is_potato<potato<T>> : std::true_type {}; template <class T> struct potato { using value_type = T; struct baked { using parent = potato; template <class O, std::enable_if_t<is_potato<typename O::parent>::value, int> = 0> baked(const O& p) : something(static_cast<typename O::parent::value_type>(p.something)) { } baked() = default; T something; }; // ... }; 

暂无
暂无

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

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