Click here to Skip to main content
15,878,809 members
Articles / General Programming / Algorithms
Tip/Trick

Execute Member Function If It Is Present

Rate me:
Please Sign up or sign in to vote.
4.94/5 (7 votes)
12 Sep 2015MIT1 min read 13.7K   20   10   2
Using C++ templates? Wish your template algorithm will be versatile and ready to work with the classes, which do not fully support the required interface? Want more functional programming with C++? Get it now!

Introduction

I had encountered this problem when working with strings. My class supports the hash code generation, but the std::string is not, while the template algorithm benefits on it. What to do? The solution is SFINAE.

Background

SFINAE - Substitution Failure Is Not An Error.

This rule applies during overload resolution of function templates: When substituting the deduced type for the template parameter fails, the specialization is discarded from the overload set instead of causing a compile error.

This feature is used in template metaprogramming.

Using the Code

The header module itself: (I called it "FuncUtils.h"):

C++
#ifndef FuncUtilsH
#define FuncUtilsH

#include <utility>

#define EXEC_MEMBER_PROC_IF_PRESENT(ProcName) namespace ProcName {\
  void ExecIfPresent(...) throw() {}\
  \
  template <class C, typename... TArgs>\
  void ExecIfPresent(C& obj, TArgs&... args) {\
    obj.ProcName(std::forward<TArgs>(args)...);\
  }\
};

// If NOT exists - returns the 'DefaultValue'
// 'DefaultValue' SHOULD be the same type as a decltype(*.FuncName())
// Works with static/const/virtual funcs
#define EXEC_MEMBER_FUNC_IF_PRESENT(FuncName, DefaultValue) namespace FuncName {\
  template <typename TReturnType = decltype(DefaultValue)>\
  auto ExecIfPresent(...) -> TReturnType {\
    return std::move(DefaultValue);\
  }\
  \
  template <class C, typename... TArgs>\
  auto ExecIfPresent(C& obj, TArgs&... args)\
   -> decltype(obj.FuncName(std::forward<TArgs>(args)...))\
  {/* do NOT use 'const C& obj' NOR 'C::FuncName()!'*/\
    return std::move(obj.FuncName(std::forward<TArgs>(args)...));\
  }\
};

#endif // FuncUtilsH

To use it, just "instantiate" a macro, providing function name and default value (which can be a constant, a literal, a reference, a class member, etc.):

C++
EXEC_MEMBER_FUNC_IF_PRESENT(getHashIfKnown, size_t())

Calling:

C++
const auto hash = getHashIfKnown::ExecIfPresent(str);

Points of Interest

This module is just a small part of the library, which uses C++11 features and which I am working under now, I decided to make it a public property.

History

Update 1

Test code for Ideone online compiler:

C++
// <Include the above code>

// While my MS VS Community 2013 Update 5 ok with 'size_t()' as a default val.,
//  the Ideone wouldn't compile it, so changed to '0U' literal
EXEC_MEMBER_FUNC_IF_PRESENT(getHashIfKnown, 0U);

#include<cassert>
#include<cstring>
#include<string>
#include<iostream>

int main() {
 std::string str = "test str";
 auto hash = getHashIfKnown::ExecIfPresent(str);
 assert(!hash);
 std::cout << "str: " << hash << std::endl;
 
 struct MyStr {
     MyStr(const char* str) throw() {
         if(str) {
             strcpy(buf, str);
             len = strlen(buf);
         }
     }
     
     size_t getHashIfKnown() const throw() {
         size_t hash = 0U;
         for(size_t idx = 0U; idx < len; ++idx) {
             hash += buf[idx] * (idx + 1U);
         }
         return hash;
     }
     
     size_t len = 0U;
     char buf[256U];
 } myStr = "we don't need no water!";
 
 hash = getHashIfKnown::ExecIfPresent(myStr);
 assert(hash);
 std::cout << "myStr: " << hash << std::endl;
}

Output:

str: 0
myStr: 24355

Update 2

GitHub repository link added.

Update 3

Downloadable archive is replaced with the new fixed, updated AND redesigned version 1.01.

Note that actual changes made are NOT described NOR even mentioned in the article's text (which is represented in the original version), you can see them in the GitHub repository:

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer (Senior) https://www.simbirsoft.com
Russian Federation Russian Federation
C/C++ dеvеlopеr (MS VS/WinAPI)

Comments and Discussions

 
QuestionWOW! Pin
koothkeeper14-Sep-15 11:25
professionalkoothkeeper14-Sep-15 11:25 
AnswerRe: WOW! Pin
Shvetsov Evgeniy15-Sep-15 5:52
professionalShvetsov Evgeniy15-Sep-15 5:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.