我的目标是实现一个谓词,该谓词检测嵌套using别名(或typedef)的存在,该别名充当轻量级标签以指示类具有某些属性(用于通用编程).例如,has_my_tag<T>谓词的行为应如下所示:
struct A {
using my_tag = void;
};
struct B {};
int main()
{
static_assert(has_my_tag<A>::value, ""); // evaluate to true if my_tag=void is present
static_assert(!has_my_tag<B>::value, ""); // false otherwise
}
Run Code Online (Sandbox Code Playgroud)
用户@JoelFalcou将此称为"轻量级分类习惯用法",并在此答案中提供了解决方案.我一直无法找到任何关于该名称的成语的引用(你知道吗?)这是Joel的实现has_my_tag<>:
template<class T, class R = void>
struct enable_if_type { typedef R type; };
template<class T, class Enable = void>
struct has_my_tag : std::false_type {};
template<class T>
struct has_my_tag<T, typename enable_if_type<typename T::my_tag>::type> :
std::true_type
{};
Run Code Online (Sandbox Code Playgroud)
这是Compiler Explorer上的一个工作版本:https://godbolt.org/z/EEOBb-
我想出了以下简化版本:
template<class T, class Enable = void>
struct has_my_tag : std::false_type {};
template<class T>
struct has_my_tag<T, typename T::my_tag> : std::true_type
{};
Run Code Online (Sandbox Code Playgroud)
我的问题:简化版是否是实现成语的可接受方式?是否存在失败的情况?是否有一个更简单的版本适用于C++ 11?我更喜欢哪个版本?
根据我的理解,Joel的版本允许my_tag别名任何类型,而我的版本需要my_tag别名void.但鉴于为轻量级谓词测试标记类型的目标,我不清楚哪个版本是首选.
辅助问题:此外,这个成语还有其他名称吗?它是否在我可以调查的任何库中使用?到目前为止,我还没有找到能够显示任何搜索结果的名称.
对于您的设置,原始版本与您的版本没有区别.两者都使用SFINAE来选择正确的has_my_tag.你的版本没有限制但是你typedef/using要my_tag=void.如果my_tag被typedef为任何其他类型,您的专业不匹配,你最终会实例化了主模板可以看出这里.
原因是你在main中实例化模板,static_assert(has_my_tag<A>::value, "");你没有指定第二个参数,所以使用了默认值(void),即has_my_tag<A,void>::value
您的专业化必须与此相匹配才能考虑.
的使用enable_if_type,(基本上做的工作void_t在C++ 17)是在上启用SFINAE ::type的T成员,但后来总是导致无效的,这样你的专业化将匹配时::type存在的类型,无论my_tag的typedef .
这让你只关心它是否存在,而不是它的类型;
就个人而言,我会使用不依赖于my_typetypedef'd为void的方法,无论是enable_if_type版本,还是类似......
#include <iostream>
#include <type_traits>
struct A {
using my_tag = void;
};
struct B {};
struct C {
using my_tag = int; // with void_t also works with my_tag = int
};
struct D {
struct my_tag{}; //or some struct as the tag
};
// same as your enable_if_type
template <typename...>
using void_t = void;
template<class T, class Enable = void>
struct has_my_tag : std::false_type {};
template<class T>
struct has_my_tag<T, void_t<typename T::my_tag>> : std::true_type
{};
int main() {
std::cout << has_my_tag<A>::value << std::endl;
std::cout << has_my_tag<B>::value << std::endl;
std::cout << has_my_tag<C>::value << std::endl;
std::cout << has_my_tag<D>::value << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)