以下程序运行良好:
struct M; // forward declare so compiler will recognize this type
struct N;
template< typename J > struct B { template< typename U > void Func1(); };
template<> template<> void B< M >::Func1< M >() {}
template<> template<> void B< N >::Func1< N >() {}
template<> template<> void B< M >::Func1< N >() {} // illegal specialization for this app
template< typename J > struct C { template< typename U > void Func2(); };
template<> template<> void C< M >::Func2< M >() {}
template<> template<> void C< N >::Func2< N >() {}
template< typename G > struct H { G g; };
int main()
{
H< B< M > > hbm;
hbm.g.Func1< M >(); // ok
hbm.g.Func1< N >(); // compiles and runs, but uses a semantically illegal specialization for this app
H< B< N > > hbn;
hbn.g.Func1< N >(); // ok
H< C< M > > hcm;
hcm.g.Func2< M >(); // ok
H< C< N > > hcn;
hcn.g.Func2< N >(); // ok
return 0;
}
重要的是在编译时显式声明结构 B 和 C,并且只允许那些对应用程序有意义的特化。
但是从上面的代码中可以看出,我的下游开发人员(总有一天!)有可能创建语法上正确但语义上没有意义的模式。具体来说,应用程序只知道如何使用类和函数类型相同的类型。其余的都是无稽之谈。
这似乎是 SFINAE、约束或概念等新 C++17+ 功能之一的案例。尽管我正在阅读这些内容,但我还没有判断力做出选择。在 Alternatives 下的 cppreference 中,如果编译器有能力(我使用 VS2015),他们建议使用 Concepts 而不是 SFINAE。
将类型名 J 限制为与类型名 U 相同的好方法是什么?