C++ 是否有一个优雅的解决方案来区分模板成员函数调用中的void和non-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

有一个基类及其对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";
    }
};

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