SFINAE 优雅地检查"template template class"(在模板参数中)

SFINAE to check "template template class" (in template argument) elegantly

本文关键字:template 参数 class 检查 SFINAE      更新时间:2023-10-16

如何在模板参数中检查模板模板类的类型?

B<T>C<T>是模板类。
我想创建一个可以D<B>D<C>的类D<class BC>
只有D<B>D::f().

这是我的解决方法(演示(。它有效。

#include <iostream>
using namespace std;
class Dummy{};
template<class T>class B{};
template<class T>class C{};
template<template<class T> class BC>class D{
    //f() is instantiated only if "BC" == "B"
    public: template<class BCLocal=BC<Dummy>> static
    typename std::enable_if<std::is_same<BCLocal,B<Dummy>>::value,void>::type f(){  
    }
    //^ #1
};
int main() {
    D<B>::f();
    //D<C>::f();   //compile error as expected, which is good
    return 0;
} 

#1行很长而且很丑(使用 Dummy 来破解(。
在实际程序中,它也容易出错,特别是当B<...>C<...>可以有 5-7 个模板参数时。

有没有办法改进它?
我梦想着这样的东西:-

template<class BCLocal=BC> static
    typename std::enable_if<std::is_same<BCLocal,B>::value,void>::type f(){ 
}

为什么不直接将比较提取到一个方便的实用程序中呢?

#include <type_traits>
template<template<class...> class L, template<class...> class R>
struct is_same_temp : std::false_type {};
template<template<class...> class T>
struct is_same_temp<T, T> : std::true_type {};

那么f上的SFINAE可以简单地看起来像这样:

static auto f() -> typename std::enable_if<is_same_temp<BC, B>::value>::type {
}

无需为enable_if指定void,因为它是它提供的默认类型。

我认为,尾随返回类型也具有美化效果。


有了C++14,我们可以进一步美化。首先是变量模板。

template<template<class...> class L, template<class...> class R>
using bool const is_same_temp_v = is_same_temp<L, R>::value;

然后使用std::enable_if_t模板别名:

static auto f() -> std::enable_if_t<is_same_temp_v<BC, B>> {
}