Patrick Wright
Patrick Wright

Reputation: 1663

Enable Different Member Functions Depending On If Type Is POD

I believe this is fairly simply to achieve, but I can't figure out how.

Take the following example class:

class Example {
public:
    template <typename T>
    size_t foo(T& v) const;
};

How can I provide two implementations for this method depending on if T is a POD? I know there is an std::is_pod type trait, but I can't figure out how to have it enable the correct function.

I also need to be able to provide specific specializations for certain types of T regardless of if they are PODs or not. For example, I want to be able to write:

template <>
size_t foo<uint8_t>(uint8_t& b);

While all other types of T are chosen based upon being PODs or not.

EDIT

I have been looking at the information everyone has been giving and have come up with the following, however, this still does not work (throws a compiler error). I can't understand why.

class Example {
public:
    template <typename T, bool U = std::is_trivially_copyable<T>::value>
    size_t foo(T& v) const;
};

template <typename T>
size_t Example::foo<T, true>(T& v) const {
    //Do something if T is mem copyable
}

template <typename T>
size_t Example::foo<T, false>(T& v) const {
    //Do something if T is not mem copyable
}

Which results in "non-class, non-variable partial specialization 'foo<T, true>' is not allowed"

Upvotes: 1

Views: 220

Answers (2)

Patrick Wright
Patrick Wright

Reputation: 1663

Here is what I did to get it to work correctly:

#include <type_traits>
#include <iostream>

class Example {
public:
    Example(int a) : _a(a) {}
    
    virtual void bar() {}

    template <typename T, typename std::enable_if<std::is_trivially_copyable<T>::value, size_t>::type = 0>
    size_t foo(T& v) const {
        std::cout << "T is trivially copyable" << std::endl;
        return sizeof(T);
    }
    
    template <typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, size_t>::type = 0>
    size_t foo(T& v) const {
        std::cout << "T is not trivially copyable" << std::endl;
        return sizeof(T);
    }
    
private:
    int _a;
    int _b;
    int _c;
};

template <>
size_t Example::foo<unsigned int>(unsigned int& v) const {
    std::cout << "T is unsigned int" << std::endl;
    return sizeof(unsigned int);
}

int main() {
    Example e(10);
    
    int a;
    e.foo(a);
    
    char b;
    e.foo(b);
    
    e.foo(e);
    
    unsigned int c;
    e.foo(c);
    
    return 0;
}

The output of which looks like:

T is trivially copyable
T is trivially copyable
T is not trivially copyable
T is unsigned int

This is based upon the following Provide/enable method to in a class based on the template type

Upvotes: 0

Jimmy Loyola
Jimmy Loyola

Reputation: 337

You can do it in the following way.

#include <iostream>
#include <type_traits>

struct A {
    int m;
};

struct B {
    int m1;
private:
    int m2;
};

struct C {
    virtual void foo() {};
};

// is_pod is deprecated since C++ 20
template <typename T>
std::enable_if_t<std::is_pod_v<T>, size_t> foo(const T& pod)
{
    std::cout << &pod << " is_pod\n";
    return 0;
}

template <>
size_t foo<uint8_t>(const uint8_t& b)
{
    std::cout << int(b) << " is uint8_t\n";
    return 1;
}

template <>
size_t foo<int>(const int& b)
{
    std::cout << int(b) << " is int\n";
    return 1;
}


int main()
{
    uint8_t a = 2;
    foo(a);

    foo(22);

    // will compile
    A instance;
    foo(instance);

    // will not compile
    B b;
    //foo(b);

    // will not compile
    C c;
    //foo(c);
}

output

2 is uint8_t
22 is int
010FFA64 is_pod

Upvotes: 1

Related Questions