Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement Interface with Anonymous Class in C++

In java we can implement an interface with Anonymous class like this :

import java.util.function.Predicate;

public class Test {

    public static void main(String[] args) {
        System.out.println(testIf("", new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.isEmpty();
            }
        }));
    }

    public static <T> boolean testIf(T t, Predicate<T> predicate) {
        return predicate.test(t);
    }

}

since Java 8 :

System.out.println(testIf("", String::isEmpty));

how can we do it in c++? I wrote the following code but I'm getting compile error :

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

template <class T>
class Predicate
{
public:
    virtual bool test(T) = 0;
};

template <class T>
bool testIf(T t, Predicate<T> predicate)
{
    return predicate.test(t);
}

int main()
{
    class : public Predicate <string> {
    public:
        virtual bool test(string s)
        {
            return s.length() == 0;
        }
    } p;
    string s = "";
    cout << testIf(s, p);
    cin.get();
    return 0;
}

Error : no instance of function template "testIf" matches the argument list argument types are: (std::string, class <unnamed>)

what's wrong here? are there other ways to do it?

Thanks!

like image 711
FaNaJ Avatar asked Feb 24 '15 10:02

FaNaJ


4 Answers

what's wrong here?

For polymorphism to work, you need to pass the base class by reference (or pointer, if you prefer):

bool testIf(T t, Predicate<T> & predicate)
                              ^

With that fixed, the code works for me, although it smells rather too much of Java for my taste.

are there other ways to do it?

In C++11 or later, a lambda would be more efficient, both in terms of performance, and noisiness of code. It removes the need to define and inherit from a base class, and to call a virtual function.

template <class T, class Predicate>
bool testIf(T t, Predicate predicate)
{
    return predicate(t);
}

testIf(s, [](string const & s){return s.length() == 0;});

(Before C++11, you could do the same thing with a function object. It was slightly more verbose, but still gave shorter, more efficient code than the inheritance approach.)

like image 101
Mike Seymour Avatar answered Oct 05 '22 23:10

Mike Seymour


C++ only supports polymorphism on reference and pointer types. Change your method to

template <class T>
bool testIf(T t, Predicate<T> & predicate) 
{
    return predicate.test(t);
}

then you can also pass subclasses of Predicate to this function.

like image 25
Hoopje Avatar answered Oct 05 '22 23:10

Hoopje


You can use one pointer for function:

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

template <class T>
class Predicate
{

public:
    bool (*test)(T);
};

template <class T>
bool testIf(T t, Predicate<T> predicate)
{
    return predicate.test(t);
}

bool one_test(string e)
{
    return e.length() == 0;
}

int main()
{
    Predicate<string> p;
    p.test = one_test;
    string s = "";
    cout << testIf(s, p);
    cin.get();
    return 0;
}
like image 34
amchacon Avatar answered Oct 05 '22 23:10

amchacon


In order for this (polymorphism) to work, you have to pass the predicate by pointer or by reference to testIF:

template <class T>
bool testIf(T t, Predicate<T>* predicate)
{
    if (predicate == nullptr) return true;
    return predicate->test(t);
}

int main()
{
    class : public Predicate <string> {
    public:
        virtual bool test(string s)
        {
            return s.length() == 0;
        }
    } p;
    string s = "";
    cout << testIf(s, &p);
    cin.get();
    return 0;
}

I usually prefer to use pointers, because I tend to overlook the posibility of polymorphism, when references are used. On the other hand, it has the disatvantage, that you have to check for nullptr and the syntax is not as nice as before.

A more common way to implement this would be the use of lambdas E.g.:

template <class T,class Pred>
bool testIf2(T t, Pred predicate)
{
    return predicate(t);
}

int main()
{
    auto pred = [](const string& s){return s.length() == 0; };
    string s = "";
    cout << testIf2(s, pred );
    cin.get();
    return 0;
}
like image 27
MikeMB Avatar answered Oct 05 '22 23:10

MikeMB