3

I have the following problem: I have a class hierarchy with a base class and two sub-classes. I have implemented a resolve_type function that accepts an instance of the base class and a generic lambda (or similar). The function resolves its type and passes it to the lambda. Inside this lambda, I’d like to check the column’s type within a constexpr-if condition in order to exclude certain types. I have tried to do this with constexpr member functions in the sub-classes, which unfortunately didn’t work.

Code:

class AbstractColumn
{
};

template <typename Type>
class DataColumn : public AbstractColumn
{
public:
    constexpr bool is_reference_column() { return false; }

    void foo() {}
};

class ReferenceColumn : public AbstractColumn
{
public:
    constexpr bool is_reference_column() { return true; }
};

template <typename Functor>
resolve_type(const AbstractColumn & col, const Functor & func);

Usage:

AbstractColumn & col = ...;

...

resolve_type(col, [] (const auto & col)
{
    // col could be ReferenceColumn, DataColumn<int>, DataColumn<float>, DataColumn<double>, DataColumn<std::string> ...
    if constexpr (!col.is_reference_column()) {
        col.foo();
    }
});

Compiler Error:

Apple LLVM version 8.1.0 (clang-802.0.42)
error: constexpr if condition is not a constant expression 
if constexpr (col.is_reference_column()) {

I know that I could use decltype to get the type and then continue using some template magic, but I had hoped to find something that is a bit more readable. My project already uses boost and its hana library, so solutions could also use these two. Does anyone have any ideas?

2
  • I like the first idea more since I'm planning to define a few more functions. But are you sure you can do decltype(col)::value on a reference value? Commented Jul 22, 2017 at 19:59
  • Added a few other alternatives to the answer. Commented Jul 22, 2017 at 20:19

2 Answers 2

3

Use a static constexpr method instead.
It follows a minimal, working example:

#include<type_traits>

struct A {
    static constexpr bool is_reference_column() { return false; }
};

int main() {
    [](const auto &col) {
        if constexpr(std::decay_t<decltype(col)>::is_reference_column()) {
            // ...
        }
    }(A{});
}

Or just inherits from std::true_type/std::false_type:

#include<type_traits>

struct A: std::true_type {};

int main() {
    [](const auto &col) {
        if constexpr(std::decay_t<decltype(col)>::value) {
            // ...
        }
    }(A{});
}

Or use an intermediate class template instead of redefining continuously is_reference_column:

#include<type_traits>

template<bool refcol>
struct I {
    static constexpr bool is_reference_column = refcol;
};

struct A: I<true> {};

int main() {
    [](const auto &col) {
        if constexpr(std::decay_t<decltype(col)>::is_reference_column) {
            // ...
        }
    }(A{});
}

Plenty of alternatives, but you cannot simply use col in a constant expression just because you declared it as a const reference. col is a runtime instance of a type T, there is no chance you can use it at compile-time as you tried to do.

Sign up to request clarification or add additional context in comments.

Comments

1

I think you're overthinking this. You don't need a member function to just identify the type of the object. You can just look at the type. So at a first go, that's simply:

resolve_type(col, [] (const auto& col)
{
    if constexpr (hana::typeid_(col) == hana::type_c<ReferenceColumn>) {
        col.foo();
    }
});

Even simpler would just be to create an overload set and just use overload resolution. There are several implementations of such a mechanism floating around here, it's especially straightforward to write in C++17. Using that:

resolve_type(col, overload(
    [](ReferenceColumn const& ref){
       ref.foo();
    },
    [](auto const& other) {
    }));

1 Comment

Hi. The first code block doesn’t compile, because col is not a constant expression. The second idea sounds interesting. I’ll have a look.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.