C++ 是否有一个优雅的解决方案来区分模板成员函数调用中的void和non-void参数?
有一个基类及其对void的专门化:C++ 是否有一个优雅的解决方案来区分模板成员函数调用中的void和non-void参数?,c++,C++,有一个基类及其对void的专门化: #include <iostream> template <typename T> struct Base { typedef T result_type; result_type get_value() { return result_type(); } void process_value(result_type&&) { std::cout << "type\n
#include <iostream>
template <typename T>
struct Base
{
typedef T result_type;
result_type get_value() { return result_type(); }
void process_value(result_type&&) {
std::cout << "type\n";
}
};
template <>
struct Base<void>
{
typedef void result_type;
void get_value() {};
void process_value(/*void&&*/) {
std::cout << "void\n";
}
};
template <typename T>
struct Derived : Base<T>
{
typedef typename Base<T>::result_type result_type;
// Returning void from a function call is fine.
result_type get() { return this->get_value(); }
void invoke() {
// If T is void: error: invalid use of void expression
this->process_value(get());
}
};
int main() {
Derived<int>().invoke();
// Trigger a compilation faluure:
Derived<void>().invoke();
}
#包括
模板
结构基
{
typedef T result_type;
结果类型获取值(){返回结果类型();}
无效过程值(结果类型&&){
std::cout处理_值(get());
}
};
int main(){
派生().invoke();
//触发编译错误:
派生().invoke();
}
在调用“process_value”(C++11很好)时,是否有一个优雅的解决方案来区分void和non-void参数?一种方法是在将结果作为参数传递时用一些空类替换
void
。我不觉得它很优雅,但它很有效:
#include <iostream>
template <typename T>
struct Base
{
typedef T result_type;
result_type eval() { return result_type(); }
result_type get_value() { return result_type(); }
void process_value(result_type&&) {
std::cout << "type\n";
}
};
template <>
struct Base<void>
{
struct value_type { };
typedef void result_type;
value_type eval() { return value_type{}; }
void get_value() {};
void process_value(value_type) {
std::cout << "void\n";
}
};
template <typename T>
struct Derived : Base<T>
{
typedef typename Base<T>::result_type result_type;
result_type get() { return this->get_value(); }
void invoke() {
this->process_value(this->eval());
}
};
int main() {
Derived<int>().invoke();
Derived<void>().invoke();
}
#包括
模板
结构基
{
typedef T result_type;
结果_typeeval(){返回结果_type();}
结果类型获取值(){返回结果类型();}
无效过程值(结果类型&&){
std::cout处理_值(this->eval());
}
};
int main(){
派生().invoke();
派生().invoke();
}
为了找到更优雅的东西,我觉得您可能需要重构原始问题。稍微重构一下,然后使用C++11,这是解决问题的另一种方法: 首先,模板专门化和
main()
都没有改变:
template <>
struct Base<void>
{
typedef void result_type;
void get_value() {}
void process_value( void ) {
std::cout << "void\n";
}
};
int main() {
Derived<int>().invoke();
// Trigger a compilation faluure:
Derived<void>().invoke();
}
正如您所看到的,我已经删除了get()
,这样可能会也可能不再符合您的意图。似乎您试图做的是创建一个类型为T
的临时对象,然后询问它。这一部分是不变的,但是它的语义被移动到Base
类,该类使用SFINAE做正确的事情
我创建了一个方便的函数is\u not\u void()
和一个模板化的Enable\u if
(Stroustrup之后),使代码更易于阅读
#include <iostream>
#include <type_traits>
template <typename T>
constexpr bool is_not_void() {
return !std::is_void<T>::value;
}
template <bool C, typename T>
using Enable_if = typename std::enable_if<C, T>::type;
如您所见,模板有一个默认的第二个模板参数,只有当类型不是void
时,才能实例化该参数。其效果是,除了void
类型之外,它们将始终与所有类型匹配,但是在类型为void
的情况下,将使用void
专门化。如您所知,即使是void&
参数的声明也会导致编译失败,这就是为什么我们不能在process\u value
的参数列表中使用Enable\u if
运行时,此代码生成:
type
void
我担心这个答案是最好的选择。然而,我将使一个类(称之为)不在Base之外,并使其成为result_类型。
template <typename T>
struct Base
{
typedef T result_type;
template <typename U, typename = Enable_if<is_not_void<U>(), U>>
U get_value() { return U(); }
template <typename U, typename = Enable_if<is_not_void<U>(), U>>
void do_process_value( U&&) {
std::cout << "type\n";
}
void process_value() {
do_process_value(get_value<T>());
}
};
type
void