SFINAE:编译器不选择专门的模板类 [英] SFINAE: Compiler doesn't pick the specialized template class
问题描述
我有 SFINAE 问题:
在下面的代码,我想C ++编译器选择专门的函子并打印特殊,但它是打印一般。
#include< iostream>
#include< vector>
template< class T,class V = void>
struct Functor {
void operator()()const {
std :: cerr<< 一般< std :: endl;
}
};
template< class T>
struct Functor< T,typename T :: Vec> {
void operator()()const {
std :: cerr<< 特殊<< std :: endl;
}
};
struct Foo {
typedef std :: vector< int> Vec;
};
int main(){
Functor< Foo> ac;
ac();
}
如何修复它,以便自动使用专门的结构?注意我不想直接专门化 Functor
结构在 Foo
,但我想专门化它在所有类型有 Vec
类型。
PS:我使用的是g ++ 4.4.4
很抱歉,在最后一个答案中误导你,我想了一会儿会更简单。所以我会尽量在这里提供一个完整的解决方案。解决这类问题的一般方法是编写一个 traits 帮助模板,并与 enable_if
(C ++ 11,boost或手动执行)决定类别专业化:
特质
方法,不一定是最好的,但是写得简单:
template< typename T&
struct has_nested_Vec {
typedef char yes;
typedef char(& no)[2];
template< typename U>
static yes test(typename U :: Vec * p);
template< typename U>
static no test(...);
static const bool value = sizeof(test< T>(0))== sizeof(yes);
};
方法很简单,提供两个模板函数,返回不同大小的类型。其中一个采用嵌套的 Vec
类型,另一个采用省略号。对于所有具有嵌套 Vec
的类型,第一个重载是更好的匹配(省略号是任何类型的最差匹配)。对于没有嵌套 Vec
的那些类型,SFINAE将丢弃该重载,并且留下的唯一选项将是省略号。所以现在我们有一个特性来询问是否任何类型都有嵌套的 Vec
类型。
启用if
您可以从任何图书馆使用,或者您可以自己翻译,这很简单:
模板< bool state,typename T = void>
struct enable_if {};
template< typename T>
struct enable_if< true,T> {
typedef T type;
};
当第一个参数为 false
基本模板是唯一的选项,并且没有嵌套的类型
,如果条件为 true
,则 enable_if
有一个可以用于SFINAE的嵌套类型
。
实现
现在,我们需要提供模板和专门化,只使用嵌套 Vec
:
template< class T,class V = void>
struct Functor {
void operator()()const {
std :: cerr<< 一般< std :: endl;
}
};
template< class T>
struct Functor< T,typename enable_if< has_nested_Vec< T> :: value> :: type> {
void operator()()const {
std :: cerr<< 特殊<< std :: endl;
}
};
每当我们用类型实例化 Functor
编译器将尝试使用专门化,这将反过来实例化 has_nested_Vec
并获得真值,传递到 enable_if
。对于值为 false
, enable_if
的类型,没有嵌套的类型
类型,因此专门化将在SFINAE中丢弃,并使用基本模板。
/ p> 在你的特定情况下,似乎你不需要专门化整个类型,而只是运算符,你可以将三个元素混合成一个:基于 I have an SFINAE problem: In the following code, I want the C++ compiler to pick the specialized functor and print "special", but it's printing "general" instead. How can I fix it so that the specialized struct is used automatically? Note I don't want to directly specialize the P.S.: I am using g++ 4.4.4 Sorry for misleading you in the last answer, I thought for a moment that it would be simpler. So I will try to provide a complete solution here. The general approach to solve this type of problems is to write a traits helper template and use it together with Trait A simple approach, not necessarily the best, but simple to write would be: The approach is simple, provide two template functions, that return types of different sizes. One of which takes the nested Enable if You can use this from any library, or you can roll your own, it is quite simple: When the first argument is Implementation Now we need to provide the template and the specialization that will use SFINAE for only those types with a nested Whenever we instantiate Your particular case In your particular case, where it seems that you don't really need to specialize the whole type but just the operator, you can mix the three elements into a single one: a
这篇关于SFINAE:编译器不选择专门的模板类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
Vec
的存在分派到两个内部模板函数之一的函子 c> c $ c> enable_if
和traits类:
template< typename T>
class Functor {
template< typename U>
void op_impl(typename U :: Vec * p)const {
std :: cout< 专门;
}
template< typename U>
void op_impl(...)const {
std :: cout< 一般;
}
public:
void operator()()const {
op_impl< T>(0);
}
};
#include <iostream>
#include <vector>
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename T::Vec> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
Functor
struct on Foo
, but I want to specialize it on all types that have a Vec
type.enable_if
(either C++11, boost or manual implementation) to decide a class specialization:template <typename T>
struct has_nested_Vec {
typedef char yes;
typedef char (&no)[2];
template <typename U>
static yes test( typename U::Vec* p );
template <typename U>
static no test( ... );
static const bool value = sizeof( test<T>(0) ) == sizeof(yes);
};
Vec
type and the other takes ellipsis. For all those types that have a nested Vec
the first overload is a better match (ellipsis is the worst match for any type). For those types that don't have a nested Vec
SFINAE will discard that overload and the only option left will be the ellipsis. So now we have a trait to ask whether any type has a nested Vec
type.template <bool state, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true,T> {
typedef T type;
};
false
, the base template is the only option, and that does not have a nested type
, if the condition is true
, then enable_if
has a nested type
that we can use with SFINAE.Vec
:template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename enable_if<has_nested_Vec<T>::value>::type > {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
Functor
with a type, the compiler will try to use the specialization, which will in turn instantiate has_nested_Vec
and obtain a truth value, passed to enable_if
. For those types for which the value is false
, enable_if
does not have a nested type
type, so the specialization will be discarded in SFINAE and the base template will be used.Functor
that dispatches to one of two internal templated functions based on the presence of Vec
, removing the need for enable_if
and the traits class:template <typename T>
class Functor {
template <typename U>
void op_impl( typename U::Vec* p ) const {
std::cout << "specialized";
}
template <typename U>
void op_impl( ... ) const {
std::cout << "general";
}
public:
void operator()() const {
op_impl<T>(0);
}
};