In any C++ program, calling a function that hasn't been declared obviously leads to a compilation error. Detecting the interface of a class lets the programmer check the presence of a given public member function or data without generating such errors, allowing him to specify a different behavior when the member doesn't exist. Interface detection doesn't use any inheritance properties and, as such, offers new cleaner and safer solutions. This article describes a way to implement such detection facilities, by exploring and explaining some advanced C++ topics.

Suppose we want to write a container class that provides all standard container operations such as push, pop, insert, etc. and adds new functionalities unseen in any other container. We will call this new container class MetaContainer. Its implementation relies on a given classic container -- typically STL ones such as std::vector and std::list -- but user defined containers are also accepted. Consequently, the MetaContainer class defines a template parameter that accepts a basic container class.

Usage

The programmer can then choose the underlying container to tune performance. For example, if a lot of insertions in the middle of the collection are performed, std::list is a better choice than std::vector. However, the Container template argument isn't forced to follow a strict interface. For instance, std::list provides a remove function whereas std::vector does not. The MetaContainer class does provide a remove function though, whose implementation calls the remove function of the underlying container, along with other internal operations.

If the underlying container class, such as std::vector or some other user container, doesn't declare a remove function, then a generic, low performance remove algorithm is used. To apply this strategy, we need to answer the following question: How can we know whether the container class has a remove function, so that we can silently switch to the generic remove implementation when the container doesn't provide one?

Pointers to each of the aforementioned members adopt a homogeneous syntax:

Member

Pointer

MF

&MyClass::MF

MD

&MyClass::MD

Static_MF

&MyClass::Static_MF

Static_MD

&MyClass::Static_MD

Because the syntax of pointers to members includes the name of a class, such pointers can be dependent names. In contrast, pointers to ordinary functions or data can't. A dependent name is a name that depends on a template parameter. For example:

Notice how the type of a pointer to a static member function can be misleading. A non-static member function follows a specific convention: it adds an implicit parameter that accepts a pointer to an object. A static member function doesn't apply to an object and doesn't have an implicit object parameter. A pointer to such a function has the same type as an ordinary function pointer.1 The important point here is that pointers to non-static and static member functions have different types that are incompatible with each other.

SFINAE, an acronym for "Substitution Failure Is Not An Error," is a principle that works during function overload resolution as follows: if the instantiation of a template function produces an invalid parameter or return type, the compiler silently removes the ill-formed function instantiation from the overload resolution set. For example:

Without SFINAE, the second call would have generated an error during the substitution of the template parameter in #1. The result of the instantiation of #1 from the second call is: void f( typename int::Type ) {}. Thanks to SFINAE, the resulting function instantiation doesn't generate an error because there is another function that matches the call.

As pointed out in the introduction, using the identifier of an undeclared function generates a compilation error. Checking if a function exists logically necessitates the use of its identifier, as we don't use any inheritance property or any extra information. We must find a mechanism that doesn't generate an error when the identifier refers to an undeclared function. SFINAE fits well in this task.

Since member function pointers can be dependent names, we could use the SFINAE principle on them. However, SFINAE is applied to the parameter type or return type of a function. A member function pointer isn't a type and can't be directly used in a function signature. To overcome this, the function pointer is used as a template argument:

template < void (MyClass::*)() >
struct TestNonStatic { };

With the TestNonStatic structure, we can use a pointer to a non-static member function in a parameter or return type of a function:

template < class T >
TestNonStatic<&T::foo> Test( );

SFINAE doesn't generate an error as long as there is another function in the overload resolution set. We need to declare a function that will be used as a "fallback" when the member function -- foo, in the example -- doesn't exist. A function with the ellipsis parameter is the right candidate for this job since such a function always has the lowest priority in the overload resolution process and matches any argument.

template < class T >
void Test( ... );

A function with the ellipsis parameter is always the lowest priority function in an overload resolution set, isn't it? The C++ standard says yes, Visual C++ 8 says yes, GCC says no for our case.2The alternative solution is to simply use the TestNonStatic structure as a parameter to the Test function instead of a return type.

The next step is to find a way of knowing at compile-time which Test function will be selected. The trick commonly used in template metaprogramming is to specify a different return type for each function declaration and employ sizeof on a call of the function. The return types must then have different sizes to obtain different results from sizeof. The sizeof operand isn't evaluated. That's why the function called inside sizeof doesn't need to be defined. The following example determines whether the class MyClass contains a member function void foo():

The final step is to wrap the whole mechanism into a reusable class from which you can specify the class and function signature to test. However, the identifier of a function -- in the above example, foo -- can't be specified as a parameter of the reusable class. Preprocessor macros are provided in the current interface detection implementation in order to deliver this need. Usage of those macros is detailed in the last chapter.

Last consideration: what about constant member functions? The above code doesn't detect them. If the user specifies a constant member signature to the reusable detector class, it won't compile because as we use the given function signature to construct the template parameter of the TestNonStatic structure, we use it also for the TestStatic structure. Static member functions can't be constant; there is no implicit object to apply the constant qualifier. Using two interfaces, one for detecting member functions and one for constant member functions, would be too cumbersome for the user.

Adding a test structure with a constant member signature to the detector class seems to deal with the problem:

template < void (MyClass::*)() const >
struct TestNonStaticConst ;

Simply putting together the functions Test( TestNonStatic< &T::foo >* ) and Test( TestNonStaticConst< &T::foo >* ) in the same overload set would lead to an ambiguous resolution error when the given class has both a constant member function and non-constant member function with exactly the same signature. We need to lower the priority of one of the two functions by using the ellipsis as a second parameter:

After seeing how to implement member function detection, doing the same for data members is straightforward. It is, in fact, easier since we don't have to care about the constant members problem. The only changes concern the template parameter of the TestStatic and TestNonStatic structures:

Access checking error

Only public members are concerned by the interface detector. However, if a function given to the detector happens to exist in a private or protected section of the class, the compiler will issue an "access denied" error. Because class member access checking comes after name look-up and overload resolution, SFINAE won't silence the error.

This section lists non-standard errors generated by the latest C++ compilers. Of course, earlier compilers that don't fully support templates -- such as Visual C++ 6 -- are likely to give some errors, but they aren't listed here. The following table represents the detection capabilities and bugs from the currently tested compilers:

Simple member function

Overloaded member function

Member function template specialization

Data member

Visual C++ 8

Visual C++ 7.1

GCC 4.1

Comeau

Visual C++ data member detection bug

In Visual C++, a dependent name consisting of a pointer to a static or non-static data member gives an error during the substitution if the data member isn't of a built-in type.Example:

The above code is well-formed according to the C++ standard. GCC and Comeau compile it, but not Visual C++. It leads to a pernicious effect in our interface detector since the data member detection is included in a SFINAE mechanism and therefore won't generate errors. This leads to the fallacious behavior of returning the NOT_FOUND value, although the data member is indeed present. For this reason, the data member detection macros are disabled for Visual C++.

The interface detector checks the exact signature with no conversion. For example, if you want to check the presence of void foo(int), you won't be able to detect a compatible function such as void foo(double). An important side-effect of this limitation is the impossibility of detecting an inherited function. This is because the type of the implicit parameter of such functions is a pointer to the parent class from which the function is declared.

The second limitation is the possible semantic difference between the detected function and the actual use of the function. For instance, in biology, some cells can be cloned. I can check this "clonable" capability by detecting whether the object contains a clone function. However, some classes that aren't even cells may declare a clone function that has other purposes, i.e. virtual constructor.

The utilization of the provided interface detector relies on 4 macros:

CREATE_FUNCTION_DETECTOR

CREATE_DATA_DETECTOR

DETECT_FUNCTION

DETECT_DATA

The first two macros are needed to construct the detector from the identifier of the function or the data to be detected. This is the first step before proceeding to the actual detection. For example, if I want to detect the function int foo (double), I need first to construct the detector:

CREATE_FUNCTION_DETECTOR(foo);

Note that once the detector for foo is constructed, any signature associated with the identifier foo can be detected: int foo(double), void foo(), etc. The DETECT_FUNCTION and DETECT_DATA macros perform the detection. The first argument of those two macros is the name of the class subject to the detection. The rest of the arguments follow the declaration syntax of the function or data to be detected, except that commas are needed around the identifiers to separate them from the rest of the type:

All of those constants belong to the Detector namespace. As a simple example, suppose that we want to check whether a class contains the member function void Print(). We use the function if it's available. Otherwise, we print a "No Print function available" message. We'll test the 2 following structures:

Second, we have to define a structure that will be used to select a different behavior according to the presence of the function. The first template parameter of the structure will be used to hold the result of the DETECT_FUNCTION macro. The second parameter is the class we want to test:

The process of selecting the correct behavior is done at compile-time. A whole class interface can be checked at once. For example, let's say that any object that can fly and quack is a duck. To know whether a class represents a duck according to this definition, we can check if both the Fly and Quack functions are present within a single expression:

This way, a simple and understandable expression can be used and reused to detect whether a class is a duck. DUCK_INTERFACE( MyDuckClass ) returns Detector::NOT_FOUND if MyDuckClass doesn't strictly follow a duck interface.

Now here's the solution of the "motivating example," i.e. "How can we know whether the container class has a remove function?"

Interface detection brings unique solutions to specific problems. It can also be used to support any duck typing3 design -- such as policy-based design -- resulting in a safer, cleaner and extended design. One might also check the BCCL4 that makes this kind of design more robust. The interface detection implementation heavily relies on many advanced C++ techniques, especially template ones. As such, it has some inevitable downsides: code complexity, support only by the latest compilers, difficulty in tracking bugs exhaustively and homogeneously amongst compilers, etc. Fortunately, the next C++ standard5 should ease the programming of such template solutions.

[Article] static qualifier removed from the Test functions declarations, as we're not in the context of a class definition

07-07-2007:

[Article] Table of contents fixed

[Article] Expression "hidden object parameter" replaced by "implicit object parameter," which is the exact wording used in the C++ standard

[Article] Short explanation added about the incapability of detecting inherited functions in "Design Limitations, Exact signature"

07-03-2007:

Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

I found another vertion, based on name ambiguity, which is able to detect inheritted members. However, it cannot recognize member type. It only generates the result of whether a member with specific name exists ... I wonder whether that code will still work if a new improvement C++ standard is promoted ...

Hello ,How are you today ? .I hope you are fine and all is well with you, My name is miss glory i saw your profile at codeproject.com which really interest me and i decide to communicate with you, and it will please me if you will be my friend, Here is my direct email address (glory_west10@yahoo.in),so that i will tell you more about me and my picture hope to hear from youGlory. ( glory_west10@yahoo.in)

Unfortunatly, I don't think there is a workaround for this on VC71, as far as I know. You must either change your compiler or use another design which doesn't include template member function detection.

I will update my article soon to include this compiler specific problem.

Thanks.So I have to save some money from now.Anyway,I tested this Interface Detection technicology on overloaded function,and the detection failed in weird way:If a function has any overloaded function in class,then neither the function nor its overloaded function can be detected.If a function has only itself without any overload,then it can be detected.

If class TestCls has both void MemFun(Param<0>) and void MemFun(Param<1>) then the none of them can be detected.If class TestCls has only void MemFun(Param<0>) or void MemFun(Param<1>) ,then that member function can be detected.

How did this happen I thought the difference between the type of function's argument is enough information for complier to find the right function.is there any workaround for this ?

And,may I have your E-mail address for further discussion?This is mine:zc@kinghoo.net.

Anyway,I tested this Interface Detection technicology on overloaded function,and the detection failed in weird way:If a function has any overloaded function in class,then neither the function nor its overloaded function can be detected.If a function has only itself without any overload,then it can be detected.

It works fine on Visual C++ 8 or GCC 4.1. I guess it's still a Visual C++ 7.1 specific error.

Does it work with overloaded functions that don't contain any template argument ?

neohost wrote:

I thought the difference between the type of function's argument is enough information for complier to find the right function.

Indeed, Param<1> and Param<2> are different types. Maybe Visual C++ 7.1 has problem with his function name decoration when template parameters are involved.

neohost wrote:

And,may I have your E-mail address for further discussion?This is mine:zc@kinghoo.net.

I'll send you mine. If some of your comments/questions concern directly the interface detection solution, it would be preferable to post them here, though.

It works fine on Visual C++ 8 or GCC 4.1. I guess it's still a Visual C++ 7.1 specific error.
Indeed, Param<1> and Param<2> are different types. Maybe Visual C++ 7.1 has
problem with his function name decoration when template parameters are involved.

Does it work with overloaded functions that don't contain any template
argument ?

Unfortunately,No.I also tested it with overloaded functions that contain onlyOriginal Data Type argument(s),and it didn't work either.

I'll send you mine. If some of your comments/questions concern directly
the interface detection solution, it would be preferable to post them here,
though.

Thanks,I will.Nice discussion with you.BTW,I've found a way to Detecting inherited member function(s),not directly and not very well,but if you can take a look at my code and offer any comment or suggestion ,that will be nice.

PS:Ｉjust found that there is two c++ key word __if_exist and __if_not_exist can do something like this Interface Detection thing but only at run-time.

Thanks,I will.Nice discussion with you.BTW,I've found a way to Detecting inherited member function(s),not directly and not very well,but if you can take a look at my code and offer any comment or suggestion ,that will be nice.

Sure. Either post here or mail it to me.

neohost wrote:

PS:Ｉjust found that there is two c++ key word __if_exist and __if_not_exist can do something like this Interface Detection thing but only at run-time.

I didn't know about such keywords.

Those C++ keywords are a Microsoft Visual C++ extension.It isn't standard C++ and not portable. In fact, the __if_exists and __if_not_exist keywords work at compile-time, but they can only check if an identifier exists, they can't check the whole signature or type. Thus, it provides more flexibility than interface detection, but greatly magnifies the semantic discrepancy problem. For instance, in the motivating example of the article, I wanted to check whether a container had a remove function. std::list provides the remove function which takes, as a parameter, the value of the object to remove. However, other user containers may take as a parameter to their remove function the index of the object to remove. If we just rely on the __if_exists keyword, the remove function will be called with a right argument for some container and a wrong argument for others resulting in either a compilation error or an incorrect behavior, if some conversions are possible.

Yes,I can't agree more.These keywords can be used for convenience,but it's not portable and can be very dangerous some time.So I won't use it.Besides,Interface Detection is more powerful.You did a wonderful work.

About that limitation that It is impossible to detect an inherited function,If it is possible to get type info of base class,then this interface detection can be used on base class,then the inherited function can be detected.I've write some code to tried this.

To detect a inherited function like this, the "ParentClass" or something like this must be injected into the class and it's base class.So, there is still a big limitation,that,this can't work with library/framework that you can't modify.any comment or suggestion is good.

To detect a inherited function like this, the "ParentClass" or something like this must be injected into the class and it's base class.So, there is still a big limitation

Indeed, it's an important limitation.For instance, in my motivating example, I wrote a MetaContainer class which can be used with any user container. I don't have any other information than the type of the container.

Interface detection should be generally considered as a last resort when you develop a project that isn't a reusable library, i.e. a stand-alone project. In such case, the recommended compile-time design, for the kind of problems covered by interface detection, is to define interfaces through abstract base classes, and use the IsDerivedFrom idiom.

If IsDerivedFrom< SupportedContainer, MyContainer >::check returns true, I know I can use insert, remove, ... safely.

Other designs such as traits can also be considered for this kind of problem..

If you are doing some maintenance on an existing project, maybe interface detection can be useful since it might be the fastest solution, requiring the least number of changes in the existing project. Then, in this case, your solution to detect inherited functions may be the lightest. Your solution seems to work except when multiple inheritance is involved (defining ParentClass as a recursive structure such as a typelist, to contain all parent classes, should deal with multiple inheritance).Though, it can't be integrated to the interface detection solution, since the whole purpose of it is to detect the interface of a class without extra-informations, so that it can be used in any context.

Sorry for didn't reply for a long time.I'm being busy with some stuff these days.I've read your every reply carefully,and I learned so much for these code and suggestions,really appreciated.Thanks.I think i've figured out all questions about this subject with your help,but there must will be some new came out.I'm expecting these questions and also your new articles.

I really enjoyed reading this article. I once needed the ability to detect at compile time whether a class implemented its own clone() method, and throw a compile-time error if not, and I came up with something very similar involving SFINAE and reference-to-class-member template parameters. This is a very nice way to enforce design policies (in my case, without this technique, forgetting to implement a clone() method would not have caused any compile-time errors to be generated, but would have resulted in subtle runtime problems). It bugged me that there was no way to treat the method identifier abstractly, but your preprocessor-based solution is a good compromise. You've covered much of the same ground as I did, though more extensibly.

I also needed the ability to detect some member functions and I noticed no serious and complete work had been done on the subject (as far as I searched). Because I had time to spend, I decided to write a reusable facility to do this kind of detection (the impossibility to treat the identifier abstractly was indeed annoying) and I tried to be as exhaustive as I can.