Sfinea in C ++

Source: Internet
Author: User

Sfinea in C ++

Author: Tang Feng
Source: http://www.cnblogs.com/liyiwen
The copyright of this article is shared by the author and the blog Park. You are welcome to repost it. However, please keep this statement and provide the original article connection clearly on the article page. Otherwise, you will be held legally liable.

Sfinae (substitution failure is not a error) is mainly used for template functions. It means that when the compiler replaces the template type parameter with a specific type and instantiates the template (expanding the template, if the replacement fails, the compilation error is not directly triggered, but the template is simply removed from the reload candidate.

Let's take a look at the code (an example often encountered in sfinae ):

Code Segment 1:

template <typename T>bool is_class(int T::*) {    return true;}template <typename T>bool is_class(...) {    return false;}struct Test {};int main(void) {    std::cout<<is_class<Test>(0)<<endl;    std::cout<<is_class<int>(0)<<endl;}

The running result is output:

1

0

This indicates that if the template parameter passed to is_class is a class, the version that returns true will be selected; otherwise, the version that returns false will be selected. This is because sfinae is working.

Why should I mention sfinae?

From the programmer's point of view, in section 1, the result of selecting the corresponding function is very intuitive and expected. It is similar to the normal function overload.

For example, for the following two functions:

int max(int a, int b) {return a>b?a:b}float max(float a, float b) {return a>b?a:b}int main(void) {    float x1=3.4f, x2=3.6f;    cout<<max(x1, x2);}

For float parameters, the float version overload will naturally be selected. In terms of appearance, Segment 1 is the same. So why does segment 1 require a special sfniae?

I think, for normal function overloading, since all the information of these functions is complete, the compiler can compile these functions before they are called, no new information can be added to these functions, and code execution can be directly generated. At the function call point, the compiler only needs to select an appropriate function address based on the parameter information.

However, for the template function overload, the situation is different. In section 1, we analyze the call of is_class <int> (0). In the first step, regardless of the number of template parameters and the number of function parameters, both is_class implementations may match, because the matching Priority Ratio of int T: * (class member pointer... So the compiler will first try to use the first version for expansion. However, when compiling the expanded result, INT: * is invalid. Therefore, the compiler gives up expanding the function and obtains another function for expansion and gets the correct call.

Therefore, the information in the template functions is incomplete before a call (it should be said that the template functions need to be expanded), and the compiler cannot generate real Execution Code for these template functions, it only performs some basic and simple checks. All templates are not "real code". They are tools used by the compiler to generate code. When expansion is required, the compiler selects the highest priority among the appropriate candidates for instantiation (expansion ). If the expanded Code cannot be correctly compiled (such as INT: * in the above example), the compiler simply abandons this expansion and looks for other templates. Imagine that if the compiler directly produces a compilation error after the expansion fails, other functions will have no chance. This is unreasonable because: 1. this expansion failure does not mean that the template code to be expanded has a problem, because it may still be expanded successfully if it is of another type. 2. This expansion failure does not mean that the appropriate template cannot be found for the expansion type. Other templates may be used together.

Therefore, I think the significance of sfinea is:

At each call point, the compiler only finds a suitable template for the type to be instantiated for expansion, instead of expanding all the possibly appropriate overload templates (functions) for a certain instantiation ).

This is the performance of the compiler's "smart" Template Selection. The normal function overload is different. No matter whether it is called or not, or whatever type of overload is required by the call point, the compiler will compile all the functions involved in the overload one by one. If the same method is used for the template, the template will be greatly limited and meaningless.

With sfinea, when writing template code, we do not need to worry about the failure of these templates when using some types for expansion, resulting in program compilation errors, because we know that the compiler only expands them when they can be expanded. If the expansion fails, the code will not actually enter your program.

Well, before we end this article, let's look at an example of sfinea's "well-known:

Procedure 2:

template <typename T>class is_class {    typedef char one;    typedef struct {char a[2];} two;    template <typename C>    static one test(int C::*);    template <typename C>    static two test(...);public:    enum {value = sizeof(test<T>(0)) == sizeof(one)};};

This is an example in the template Bible C ++ templates (the original program may not be exactly the same). What is different from section 1 is that is_class <t> :: value is a bool value during the compilation period, and the program segment 1, true, or false is the result obtained at runtime. Is_class <t>: device such as value often appears in template compilation and is used according to a type of feature (for example, is it a class ?) To select different templates. Many similar devices are provided in boost, and boost: enable_if is used together to complete template programming with great power.

It can be said that sfinea is almost everywhere and an indispensable "principle ". :)

This article is complete.

 

 

Postscript

After studying and thinking over the past few days, I have gained the following benefits:

In http://www.martinecker.com/wiki/index.php? Title = sfinae_principle has the following section:

To summarize, the essence of the sfinae principle is this:If an invalid argument or return type is formed when a function template is instantiated during overload resolution, the function template instantiation is removed from the overload resolution set and does not result in a compilation error.

To sum up, the essence of the sfinae principle is:When a function template is instantiated, if an invalid parameter type or return type is generated, this instantiation will be removed from the overload option, but no compilation error will be generated.

This sentence is in place. Two points should be taken into account: 1. sfinae works during heavy-load resolution. 2. sfinae takes effect because an invalid parameter type or return value type is generated. Note that,This type can be the type of the returned value.! (This is very important, because sometimes you cannot perform actions on the parameter list. For example, when the operator is overloaded, the compiler has a limited number of parameters ~!)

As mentioned above:

At each call point, the compiler only finds a suitable template for the type to be instantiated for expansion, instead of expanding all the possibly appropriate overload templates (functions) for a certain instantiation ).

It is not appropriate, but it only gets the "No compilation error" side. I think sfinea is generated because the template is too intrusive and has a wide range of matching conditions, and the results are prone to conflict with each other. Therefore, sfinea must exist. But after knowing that the compiler has behavior like sfinea, cpper of "abnormal" uses it to do a lot of things that have never been thought of before, as ownwaterloo mentioned in the reply:

Sfinea deliberately utilizes the features of the C ++ language to create such a situation,

It is indeed the essence of sfinea applications. Some examples are easier to understand, but I will not give them here (because I cannot give them better, and the section on enable_if described in "Beyond C ++ standard library-Introduction to boost library" (there is no paper book on hand and the chapter cannot be determined, this section describes sfinea well. I also happened to solve the problem by using sfinea (Click here). If you are interested, you can check it out (the body and reply together ).

Before the end, let's look at something interesting:

template <typename T>struct has_memfun_hoge{private :    template < typename U, typename ... Types>    [] check() -> decltype(        reinterpret_cast<U *>(nullptr)->hoge(Types ... args),         std::true_type) ;    template < typename U >    std::false_type check() ;public :    static const bool value =         std::is_same< check<T>(), std::true_type >::value ;} ;

This is sfinae in C ++ 0x. It is used to determine whether a class has the Hoge function. Is it very simple ...... Well, yes, I copied it from the Internet.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.