基于Abstract Factory中可用的重载版本自动选择构造函数

Pig*_*pag 5 c++ templates overloading

我正在使用C++模板编写一个抽象工厂,并遇到了一个小障碍.即,泛型类T可以提供以下一种或多种方式来构造对象:

static T* T::create(int arg);
T(int arg);
T();
Run Code Online (Sandbox Code Playgroud)

我正在编写抽象工厂类,以便它可以按给定的顺序自动尝试这三种潜在的构造:

template <class T>
class Factory {
public:
    T* create(int arg) {
        return T::create(arg);  // first preference
        return new T(arg);  // this if above does not exist
        return new T;  // this if above does not exist
        // compiler error if none of the three is provided by class T
    }
};
Run Code Online (Sandbox Code Playgroud)

如何使用C++模板实现此目的?谢谢.

sky*_*ack 5

沿着这条线的东西应该工作:

struct S { static auto create(int) { return new S; } };
struct T { T(int) {} };
struct U {};

template<int N> struct tag: tag<N-1> {};
template<> struct tag<0> {};

class Factory {
    template<typename C>
    auto create(tag<2>, int N) -> decltype(C::create(N)) {
        return C::create(N);
    }

    template<typename C>
    auto create(tag<1>, int N) -> decltype(new C{N}) {
        return new C{N};
    }

    template<typename C>
    auto create(tag<0>, ...) {
        return new C{};
    }

public:
    template<typename C>
    auto create(int N) {
        return create<C>(tag<2>{}, N);
    }
};

int main() {
    Factory factory;
    factory.create<S>(0);
    factory.create<T>(0);
    factory.create<U>(0);
}
Run Code Online (Sandbox Code Playgroud)

它基于sfinae和标签调度技术.
基本思想是create将工厂的功能转发给一组内部功能.这些函数会测试您正在查找的功能,因为它们存在tag并在测试失败时被丢弃.由于sfinae,只要其中一个成功,代码就会编译,一切都按预期工作.


这是C++ 17中的类似解决方案:

#include <type_traits>
#include <iostream>
#include <utility>

struct S { static auto create(int) { return new S; } };
struct T { T(int) {} };
struct U {};

template<typename C> constexpr auto has_create(int) -> decltype(C::create(std::declval<int>()), bool{}) { return true; }
template<typename C> constexpr auto has_create(char) { return false; }

struct Factory {
    template<typename C>
    auto create(int N) {
        if constexpr(has_create<C>(0)) {
            std::cout << "has create" << std::endl;
            return C::create(N);
        } else if constexpr(std::is_constructible_v<C, int>) {
            std::cout << "has proper constructor" << std::endl;
            return new C{N};
        } else {
            std::cout << "well, do it and shut up" << std::endl;
            (void)N;
            return C{};
        }
    }
};

int main() {
    Factory factory;
    factory.create<S>(0);
    factory.create<T>(0);
    factory.create<U>(0);
}
Run Code Online (Sandbox Code Playgroud)

感谢@StoryTeller和@ Jarod42在这个艰难的早晨提供帮助.
wandbox上查看并运行.