Search code examples
c++sfinaeenable-if

sfinae: enable_if condition


I always only see enable_if is used with the condition std::is_integral::value.

Is there a way to use in the condition a function-call of a memberfunction of an object of another templateclass? The function I'm talking about should look like this:

bool someFunc()
{
    if (QString(T::staticMetaObject.className()) == QString("Form")) {
        return true;
    }
    return false;   
}

Currently I cannot get it compiled no matter what I try.

Thank you for helping me.

edit:

that my question is more clear more code and an error msg.

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include <type_traits>
#include <QDebug>

template <class T>
typename std::enable_if<Form<MainWindow>::staticThis->someFunc(),bool>::type
  is_smth (T* obj) { return true; }

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    form = new Form<MainWindow>;

    qDebug() << is_smth(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "form.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    Form<MainWindow>* form;

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

form.h

#ifndef FORM_H
#define FORM_H
#include <QObject>

class FormBase : public QObject
{
    Q_OBJECT
};

template <class T>
class Form : public FormBase
{
public:
    Form() {}

    static Form* staticThis;

    bool someFunc()
    {
        if (QString(T::staticMetaObject.className()) == QString(Form::staticMetaObject.className())) {
            return true;
        }
        return false;
    }
};

#endif // FORM_H

form.cpp

#include "form.h"
#include "mainwindow.h"

Form<MainWindow>* Form::staticThis = NULL;

error:

the value of 'Form::staticThis' is not usable in a constant expression typename std::enable_if::staticThis->someFunc(),bool>::type ^

I'm do not want to use in condition of enable_if a function from std or something. I want to use my own function. And i don't know how to get it work. Maybe thats why you will think the code is a little bit busy. But i think it should show now what I'm trying to accomplish.

Thank you again


Solution

  • Not sure about what you are looking for, but here is an example of sfinae that uses member functions:

    #include<type_traits>
    
    template<typename T>
    std::enable_if_t<std::is_member_function_pointer<T>::value>
    foo() { }
    
    struct S {
        void bar() { }
        int i;
    };
    
    int main() {
        // compiles, for it is a member function
        foo<decltype(&S::bar)>();
        // does not compile, for it is not a member function
        //foo<decltype(&S::i)>();
    }
    

    EDIT

    After the edit of the OP, I'm updating the answer with a minimal, working example that shows how to use sfinae the way he wants.
    In order to do that, the member function has to be constexpr at least for obvious reasons.

    #include<type_traits>
    
    struct S {
        static constexpr bool bar(bool b) { return b; }
    };
    
    template<bool b>
    std::enable_if_t<S::bar(b)>
    foo() { }
    
    int main() {
        foo<true>();
        // fails to compile because of sfinae
        // foo<false>();
    }
    

    The OP's example is far from being a minimal one and I guess it doesn't worth to fix it.
    Instead, the one above is enough to explain the idea behind the solution.

    EDIT

    As mentioned in the comments, C++11 has stricter limitations on constexpr functions.
    Instead you can have more complex statements in a constexpr function since C++14.
    As an example, the code below compiles using -std=c++14, whilst it doesn't compile using -std=c++11:

    #include<type_traits>
    
    struct T {
        constexpr T(char c): ch{c} { }
        char ch;
    };
    
    struct S {
        static constexpr bool bar(T&& t) {
            if(t.ch == 'y') {
                return static_cast<unsigned int>(t.ch) % 2 == 0;
            } else {
                return true;
            }
        }
    };
    
    template<char c>
    std::enable_if_t<S::bar(T{c})>
    foo() { }
    
    int main() {
        foo<'x'>();
        // fails to compile because of sfinae
        // foo<'y'>();
    }