基于运算符中的枚举值的Deduce类型?

时间:2017-06-16 18:35:58

标签: c++ c++11 templates enums

我真的想要编译以下代码:

#include <string>
#include <utility>

enum class type {
    integer, string
};

template<typename T>
struct foo {
    type type_;
    T val_;

    foo(type t) : type_{std::move(t)} {}
    static foo<T> set(T val) {
        foo<T> result;
        result.val_ = std::move(val);
        return result;
    }

    template<typename T2>
    friend foo<T2> operator|(const foo<T2>& lhs, const foo<T2>& rhs) {
        // do something
        return rhs;
    }
};

template<typename T>
void test(foo<T>) {}
int main() {
    using foo_int = foo<int>;
    using foo_string = foo<std::string>;

    // what I want (they currently all don't compile)
    test(type::integer | foo_int::set(10)); // ok
    test(type::integer | foo_int::set("hello")); // error
    test(type::string | foo_string::set("hello")); // ok
    test(type::string | foo_string::set(10)); // error
}

以上也是我目前的尝试。我认为唯一缺少的是在将T传递给构造函数时扣除type,因此它目前无法编译。我无法理解这一部分。尝试解决此问题的每一次尝试都会导致我不得不改变调用test的方式,我不想理想(但我甚至没有去过那里。)

有没有人知道如何编写最后四行编译或不编译(参见注释)?

我也找不到消除foo_intfoo_string的方法,但我可以忍受它。改变那些不理想的语义,但我想我可以忍受它,如果它是最小的(这是一个库,所以它需要保持相对简单。)

1 个答案:

答案 0 :(得分:2)

您需要重新考虑您的设计。我对模板元编程没有超级自信(这似乎是你想要做的),但这是我采取的方法:

#include<string>

enum class type {
    integer, string
};

template<type T>
struct foo_impl {
    static constexpr bool is_valid = false;
    typedef void Type;
};

template<>
struct foo_impl<type::integer> {
    static constexpr bool is_valid = true;
    typedef int Type;
};

template<>
struct foo_impl<type::string> {
    static constexpr bool is_valid = true;
    typedef std::string Type;
};

template<type T>
struct foo {
    static_assert(foo_impl<T>::is_valid, "Not a valid type!");

    using Type = typename foo_impl<T>::Type;
    Type value;

    foo(Type v) : value(std::move(v)) {}

    friend foo operator|(type const& lhs, foo const& rhs) {
        // do something
        return rhs;
    }
};

template<type T>
void test(foo<T>) {}
int main() {
    using foo_int = foo<type::integer>;
    using foo_string = foo<type::string>;

    // what I want (they currently all don't compile)
    test(type::integer | foo_int(10)); // ok
    //test(type::integer | foo_int(std::string("hello"))); // error
    test(type::string | foo_string(std::string("hello"))); // ok
    //test(type::string | foo_string(10)); // error
}

请注意,我已经遗漏了很多未实现的代码(我完全抛弃了foo::set),因为我不清楚从这段代码中意味着什么实际功能。但是,您会看到此代码在Ideone.com编译中实现,而fails to compile则在您尝试取消注释其中一行时。{/ p>

注意我必须在结尾显式构建std::string;编译器无法推断出const char *在隐式转换的上下文之外是std::string