C++ 不同的基类取决于模板参数

C++ 不同的基类取决于模板参数,c++,inheritance,c++17,C++,Inheritance,C++17,是否有可能在编译时根据类模板的参数确定类模板的确切基?例如,我有一个类模板,它在其构造函数中接受一个参数,我想用另一个参数扩展这个类,将使用另一个构造函数。问题在于,第二个实例化(具有两个参数)必须与具有一个参数的实例化具有不同的基类。我可以使用std::conditional检测适当的基类,但问题在于在一个类模板中同时使用两个构造函数。例如: #include <type_traits> struct X { }; struct Y { }; struct XX { };

是否有可能在编译时根据类模板的参数确定类模板的确切基?例如,我有一个类模板,它在其构造函数中接受一个参数,我想用另一个参数扩展这个类,将使用另一个构造函数。问题在于,第二个实例化(具有两个参数)必须与具有一个参数的实例化具有不同的基类。我可以使用
std::conditional
检测适当的基类,但问题在于在一个类模板中同时使用两个构造函数。例如:

#include <type_traits>

struct X
{
};

struct Y
{
};

struct XX
{
};

struct XY
{
};


template<class T, class V = void>
struct Z: public std::conditional_t<std::is_void_v<V>, XX, XY>
{
    Z(T&& t, V&& v)
        : XY()
    {
        // do smth with t and v
    }

    Z(T&& t)
        : XX()
    {
        // do smth with t
    }
};

int main()
{
    auto a = Z(X(), Y());
    auto b = Z(X());         // <-- this instantiation fails
}
更新:

尝试将两个参数设置为模板,如果
启用,\u
,但不起作用(与原始代码中形成对void的引用的
相同):

模板>
Z(T&T,V&V)
:XY()
{
//使用t和v进行smth
}

这不是一个优雅的解决方案,但似乎可以使用部分专门化和演绎指南

template<class T, class V>
struct Z: public XY
{
    Z(T&& t, V&& v)
        : XY()
    {
        // do smth with t and v
    }
};

template<class T>
struct Z<T, void> : public XX
{
    Z(T&& t)
    : XX()
    {

    }
};

template <class T>
Z(T&& ) -> Z<T, void>;
模板
结构Z:公共XY
{
Z(T&T,V&V)
:XY()
{
//使用t和v进行smth
}
};
模板
结构Z:public XX
{
Z(T&T)
:XX()
{
}
};
模板
Z(T&)->Z;

高级条件类定义的常用方法是依赖基类:

struct B1 {};
struct B2 {};

template<class T>
struct Z1 : B1 {
  Z1(T&&) : B1() {}
};
template<class T,class V>
struct Z2 : B2 {
  Z2(T&&,V&&) : B2() {}
};

template<class T,class V>
using Z0=std::conditional_t<std::is_void_v<V>,Z1<T>,Z2<T,V>>;

template<class T,class V=void>
struct Z : Z0<T,V> {
  using Z0<T,V>::Z0;
};
template<class T> Z(T) -> Z<T>;
template<class T,class V> Z(T,V) -> Z<T,V>;
structb1{};
结构B2{};
模板
结构Z1:B1{
Z1(T&):B1(){}
};
模板
结构Z2:B2{
Z2(T&&,V&&):B2(){}
};
模板
使用Z0=std::conditional\u t;
模板
结构Z:Z0{
使用Z0::Z0;
};
模板Z(T)->Z;
模板Z(T,V)->Z;
因为CTAD只考虑主模板(不考虑其继承的构造函数),所以需要推断指南


如果此转换产生的
Z
没有自己的成员,C++20可能会提供直接使用(此处称之为)
Z0
的机会,因为它支持别名模板的CTAD。

您可以添加尝试实例化模板的行吗?例如,错误消息中引用的行。在源代码列表中添加了注释(第二个实例化有一个参数)。这看起来像是在您的ctor上使用
std::enable_if
。@Matthew:注意,构造函数必须是一个模板才能将其删除(即使如此,也需要一些微妙的手段来延迟替换失败)@davis herring我希望能够在不指定模板参数的情况下声明
Z
的实例。这将进行编译。但是,似乎不可能直接重用
Z
中的
Z
成员,因为在通用模板
Z之前不能引用
Z
作为模板专用化de>是定义的。因此,如果
Z
是“主要像Z,加上一些与V实例相关的次要功能”,那就不可能直接实现,或者至少我不知道如何实现。@Student4K是的,我承认这不是一个“好”的方法解决方案。我只是给出一个拙见,希望得到更好的解决方案。基于这个解决方案,如果想要尽可能多地重用,也许可以添加一个额外的抽象层,比如pimpl?
template<class T, class V>
struct Z: public XY
{
    Z(T&& t, V&& v)
        : XY()
    {
        // do smth with t and v
    }
};

template<class T>
struct Z<T, void> : public XX
{
    Z(T&& t)
    : XX()
    {

    }
};

template <class T>
Z(T&& ) -> Z<T, void>;
struct B1 {};
struct B2 {};

template<class T>
struct Z1 : B1 {
  Z1(T&&) : B1() {}
};
template<class T,class V>
struct Z2 : B2 {
  Z2(T&&,V&&) : B2() {}
};

template<class T,class V>
using Z0=std::conditional_t<std::is_void_v<V>,Z1<T>,Z2<T,V>>;

template<class T,class V=void>
struct Z : Z0<T,V> {
  using Z0<T,V>::Z0;
};
template<class T> Z(T) -> Z<T>;
template<class T,class V> Z(T,V) -> Z<T,V>;