特定模板(不是类型)的模板函数特化
Template function specialization for specific template ( not type )
我有一些模板化的 class 类型,例如 A、B、C,如下所示:
template < typename T >
class A{};
template < typename T >
class B{};
template < typename T >
class C{};
现在我想要一个接受任何类型的函数,比如:
template < typename T>
void Func()
{
std::cout << "Default " << __PRETTY_FUNCTION__ << std::endl;
}
现在我想专门化该函数以仅接受给定模板之一 class,例如:
template < typename T>
void Func<A<T>>()
{
std::cout << "All A Types " << __PRETTY_FUNCTION__ << std::endl;
}
这是不允许的,因为它只是部分专业化。好的。
我觉得concept
可能会有帮助,但感觉我想的太复杂了。我的解决方案是:
template < typename T, template <typename > typename OUTER >
bool Check;
template < typename INNER, template < typename > typename OUTER, template < typename> typename T>
constexpr bool Check< T<INNER>, OUTER > = std::is_same_v< OUTER<INNER>, T<INNER>>;
template < typename T >
concept IsA = Check< T, A >;
template < typename T >
concept IsB = Check< T, B >;
template < IsA T >
void Func()
{
std::cout << "All A Types " << __PRETTY_FUNCTION__ << std::endl;
}
template < IsB T >
void Func()
{
std::cout << "All B Types " << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
Func<A<int>>();
Func<B<int>>();
Func<C<int>>();
}
我觉得有点复杂。那可以简化吗?如果可以删除 Check
模板就好了。有什么想法吗?
在此处查看完整示例live
一个常见的解决方法是这样的:
template <typename T>
struct FuncImpl {
static void Run() { std::cout << "Default"; }
};
template <typename T>
struct FuncImpl<A<T>> {
static void Run() { std::cout << "Specialized for A<T>"; }
};
template <typename T>
void Func() { FuncImpl<T>::Run(); }
函数模板不能部分特化,但 class 模板可以;所以我们只是从前者委托给后者。
OP 写道:
Yes, would be nice to write some "instant" code directly in the functions template parameter... if possible...
通常,为了确定它是否是某个给定 class 模板的特化,我们会提前定义一个特征,然后检查类型是否满足该特征。如果你不想提前定义任何东西,你必须想办法进行模板参数推导inline,你可以检查它是否成功。在 C++20 中,这很简单但有点难看:
template <typename T>
void Func()
{
std::cout << "unconstrained" << std::endl;
}
template <typename T>
requires requires {
[]<typename U>(const A<U>&){}(std::declval<T>());
}
void Func()
{
std::cout << "constrained" << std::endl;
}
此处,requires-clause 检查是否 T
可以绑定到 const A<U>&
类型的参数以用于某些可推导的 U
。你可以在这里看到这个例子:https://godbolt.org/z/dTEbaaPvh
读起来不太愉快。如果您将多次使用此 hack,我认为最好只定义特征。我回答你的问题只是为了满足你的好奇心,而不是推荐这种技术。
上面的版本不仅会在模板参数是某个 A<U>
时选择受约束的版本,而且当它可能是 cv 限定的,可能是 ref 限定的,并且可能是从 [=14= 公开派生的时].可以进行一些调整以使约束更加严格。
It feels a bit complicated to me. Can that be simplified? Would be nice if the Check template can be removed. Any idea?
很多复杂性和不雅之处在于每个 class 模板都需要一个新概念。写一个通用可重用的概念,用起来不再复杂
template <typename T, template <typename...> class TT>
constexpr bool is_instantiation_of_v = false;
template <template <typename...> class TT, typename... TS>
constexpr bool is_instantiation_of_v <TT<TS...>, TT> = true;
template <class C, template<typename...> class TT>
concept instantiation_of = is_instantiation_of_v<C, TT>;
与您的原理相同,除了检查器可用于采用任意数量类型参数的模板。同时,该概念接受相同的参数。第一个参数具有特殊含义,在简写语法中被隐式理解为受约束的模板参数。其余部分(模板模板参数)必须明确给出。
如何使用? Like this
template <instantiation_of<A> T>
int Func()
{
return 'A';
}
template <instantiation_of<B> T>
int Func()
{
return 'B';
}
有新的 class 模板来约束?没问题,这个概念不需要额外的样板就可以工作。
template <instantiation_of<D> T>
int Func()
{
return 'D';
}
我有一些模板化的 class 类型,例如 A、B、C,如下所示:
template < typename T >
class A{};
template < typename T >
class B{};
template < typename T >
class C{};
现在我想要一个接受任何类型的函数,比如:
template < typename T>
void Func()
{
std::cout << "Default " << __PRETTY_FUNCTION__ << std::endl;
}
现在我想专门化该函数以仅接受给定模板之一 class,例如:
template < typename T>
void Func<A<T>>()
{
std::cout << "All A Types " << __PRETTY_FUNCTION__ << std::endl;
}
这是不允许的,因为它只是部分专业化。好的。
我觉得concept
可能会有帮助,但感觉我想的太复杂了。我的解决方案是:
template < typename T, template <typename > typename OUTER >
bool Check;
template < typename INNER, template < typename > typename OUTER, template < typename> typename T>
constexpr bool Check< T<INNER>, OUTER > = std::is_same_v< OUTER<INNER>, T<INNER>>;
template < typename T >
concept IsA = Check< T, A >;
template < typename T >
concept IsB = Check< T, B >;
template < IsA T >
void Func()
{
std::cout << "All A Types " << __PRETTY_FUNCTION__ << std::endl;
}
template < IsB T >
void Func()
{
std::cout << "All B Types " << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
Func<A<int>>();
Func<B<int>>();
Func<C<int>>();
}
我觉得有点复杂。那可以简化吗?如果可以删除 Check
模板就好了。有什么想法吗?
在此处查看完整示例live
一个常见的解决方法是这样的:
template <typename T>
struct FuncImpl {
static void Run() { std::cout << "Default"; }
};
template <typename T>
struct FuncImpl<A<T>> {
static void Run() { std::cout << "Specialized for A<T>"; }
};
template <typename T>
void Func() { FuncImpl<T>::Run(); }
函数模板不能部分特化,但 class 模板可以;所以我们只是从前者委托给后者。
OP 写道:
Yes, would be nice to write some "instant" code directly in the functions template parameter... if possible...
通常,为了确定它是否是某个给定 class 模板的特化,我们会提前定义一个特征,然后检查类型是否满足该特征。如果你不想提前定义任何东西,你必须想办法进行模板参数推导inline,你可以检查它是否成功。在 C++20 中,这很简单但有点难看:
template <typename T>
void Func()
{
std::cout << "unconstrained" << std::endl;
}
template <typename T>
requires requires {
[]<typename U>(const A<U>&){}(std::declval<T>());
}
void Func()
{
std::cout << "constrained" << std::endl;
}
此处,requires-clause 检查是否 T
可以绑定到 const A<U>&
类型的参数以用于某些可推导的 U
。你可以在这里看到这个例子:https://godbolt.org/z/dTEbaaPvh
读起来不太愉快。如果您将多次使用此 hack,我认为最好只定义特征。我回答你的问题只是为了满足你的好奇心,而不是推荐这种技术。
上面的版本不仅会在模板参数是某个 A<U>
时选择受约束的版本,而且当它可能是 cv 限定的,可能是 ref 限定的,并且可能是从 [=14= 公开派生的时].可以进行一些调整以使约束更加严格。
It feels a bit complicated to me. Can that be simplified? Would be nice if the Check template can be removed. Any idea?
很多复杂性和不雅之处在于每个 class 模板都需要一个新概念。写一个通用可重用的概念,用起来不再复杂
template <typename T, template <typename...> class TT>
constexpr bool is_instantiation_of_v = false;
template <template <typename...> class TT, typename... TS>
constexpr bool is_instantiation_of_v <TT<TS...>, TT> = true;
template <class C, template<typename...> class TT>
concept instantiation_of = is_instantiation_of_v<C, TT>;
与您的原理相同,除了检查器可用于采用任意数量类型参数的模板。同时,该概念接受相同的参数。第一个参数具有特殊含义,在简写语法中被隐式理解为受约束的模板参数。其余部分(模板模板参数)必须明确给出。
如何使用? Like this
template <instantiation_of<A> T>
int Func()
{
return 'A';
}
template <instantiation_of<B> T>
int Func()
{
return 'B';
}
有新的 class 模板来约束?没问题,这个概念不需要额外的样板就可以工作。
template <instantiation_of<D> T>
int Func()
{
return 'D';
}