我真的想要编译以下代码:
#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_int
和foo_string
的方法,但我可以忍受它。改变那些不理想的语义,但我想我可以忍受它,如果它是最小的(这是一个库,所以它需要保持相对简单。)
答案 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
。