如何优雅地将模板参数限制为 `<Certain_Class<AnyT>>`?

How to elegantly restrict a template argument to be a `<Certain_Class<AnyT>>`?

如何优雅地将Wrapper的模板参数限制为Wrapper<Any,MyArray<AnyT>>

  1. 不要破坏内容支持 (Visual Studio)。
  2. 可读性高。不要使用 hacky 方法。
    由于某些原因,大多数解决方案都喜欢破解。
  3. 使用 C++ 语法规则使其在第一行显而易见。 (不仅仅是绿色评论)

据我所知,解法有很多,但并不是每一个解法都符合条件。

解决方法 1(模板专业化,失败 1)

template<class T> class MyArray{};
template<class T,class T2> class Wrapper;
template<class T,class T2> class Wrapper<T,MyArray<T2>>{     
    using Test=int; 
};
class B{};
class C{};
int main() {
    Wrapper<C,MyArray<B>> wrapper;
    return 0;
}

此代码修改自 (@max66)。

IDE 的上下文线索/语法高亮会被混淆。
在我的例子中,它将一些正确的类型标记为错误,例如:-

class ShowError : public Wrapper<B,MyArray<C>>{ 
    Test n=0;  //<-- unknown "Test" (intellisense)
};

解决方法 2(有些 hacky field/typedef,失败 2)

template<class T> class MyArray{ 
    public: using MyArrayT=T; 
};
template<class T,class T2> class Wrapper{
    public: using myT=typename T2::MyArrayT;
    //^ assert at compile time
};

这个想法来自 (@Jarod42)

中的评论

class 声明没有提及 MyArray,它只是使用一种 hacky(可读性较差)的方式 (MyArrayT) 来强制 T2MyArray.

解决方法 3(基础 class,失败 2)

class MyArrayBase{};
template<class T> class MyArray : public MyArrayBase{  };
template<class T,class T2> class Wrapper{
    //check something around MyArrayBase *object = new T2();
    // or "is_base_of"
};

代码修改自Restrict C++ Template Parameter to Subclass and C++ templates that accept only certain types

它与解决方法 2 有相同的缺点。
对于普通用户来说并不明显。

解决方法 4(SNIFAE,失败 1)

通过在模板 class 声明 (Wrapper) 上添加 std::enable_if,我可以获得一个有效的 hack。
不幸的是,内容支持讨厌它。

参考

这是我阅读的其他链接:-

你可以写一个自定义类型特征is_specialization,如下:

template<class Type, template<class...> class Template>
struct is_specialization
  : std::false_type {};
template<template<class...> class Template, class... TArgs>
struct is_specialization<Template<TArgs...>, Template>
  : std::true_type {};

那么您只需要 static_assert 对于给定的模板参数 is_specialization 为真:

template<class T,class T2>
class Wrapper {
    static_assert(is_specialization<T2, MyArray>::value, "T2 must be a specialization of MyArray");
};