【问题标题】:Checking if a tuple contains element of a certain type检查元组是否包含某种类型的元素
【发布时间】:2018-03-19 04:15:17
【问题描述】:

我正在尝试通过实现一些功能来学习 C++ 模板元编程。我知道这个特定问题的解决方案已经在 stackoverflow 上提供,我感兴趣的是了解为什么这个解决方案不起作用。代码如下:

template < std::size_t... Ns , typename... Ts >
auto tail_impl( std::index_sequence<Ns...> , std::tuple<Ts...> t )
{
   return  std::make_tuple( std::get<Ns+1u>(t)... );
}

template <class F, class... R >
tuple<R...> tail( std::tuple<F,R...> t )
{
   return  tail_impl( std::make_index_sequence<sizeof...(R)>() , t );
}


template<class X, class F, class... R>
constexpr bool check_for_type(tuple<F,R...> t) {
    if constexpr(is_same<F,X>::value) {
        return true;
    } 
    return check_for_type<X>(tail(t));
}


template<class X>
constexpr bool check_for_type(tuple<> t) {
    return false;
}


int main( int argc, const char *argv) {
    auto t2 = make_tuple(4,"qw", 6.5);
    double f = check_for_type<double>(t2);
    return 0;
}

这个模板应该检查一个元组是否包含某种类型的元素,但是编译它会给出以下错误:

> clang++ t.cpp -std=c++17
t.cpp:45:12: error: call to function 'check_for_type' that is neither visible in the
      template definition nor found by argument-dependent lookup
    return check_for_type<X>(tail(t));
           ^
t.cpp:45:12: note: in instantiation of function template specialization
      'check_for_type<double, double>' requested here
t.cpp:45:12: note: in instantiation of function template specialization
      'check_for_type<double, const char *, double>' requested here
t.cpp:66:16: note: in instantiation of function template specialization
      'check_for_type<double, int, const char *, double>' requested here
    double f = check_for_type<double>(t2);
               ^
t.cpp:58:16: note: 'check_for_type' should be declared prior to the call site
constexpr bool check_for_type(tuple<> t) {
               ^
1 error generated.

这段代码有什么问题?

【问题讨论】:

  • @Justin tail 接受一个元组并返回另一个没有第一个元素的输入。我将编辑代码以包含 tail 定义。

标签: c++ templates metaprogramming template-meta-programming


【解决方案1】:

由于您在代码中使用 c++17,我认为有必要指出有很多新工具可以避免制作此类递归模板。

你可以把整个事情浓缩成这样:

#include <iostream>
#include <type_traits>
#include <tuple>

template <typename T1, typename... T2>
constexpr bool check_for_type(std::tuple<T2...>) {
    return std::disjunction_v<std::is_same<T1, T2>...>;
}

int main() {
    std::tuple<int, char, bool> tup;
    std::cout << check_for_type<char>(tup) << '\n';
    std::cout << check_for_type<float>(tup) << std::endl;
    return 0;
}

如果std::disjunction 没有获取参数,则默认为false,因此此处还介绍了传递空元组。

【讨论】:

【解决方案2】:
template<class X, class F, class... R>
constexpr bool check_for_type(tuple<F,R...> t) {
    if constexpr(is_same<F,X>::value) {
        return true;
    } 
    return check_for_type<X>(tail(t));
}

您在声明之前调用了check_for_type&lt;X&gt;(...)。有用的是,您的错误消息指出:

t.cpp:58:16: note: 'check_for_type' should be declared prior to the call site
constexpr bool check_for_type(tuple<> t) {

一旦你这样做了,代码compiles

// Put this function first
template<class X>
constexpr bool check_for_type(tuple<> t) {
    return false;
}

template<class X, class F, class... R>
constexpr bool check_for_type(tuple<F,R...> t) {
    if constexpr(is_same<F,X>::value) {
        return true;
    }
    // Right here, the compiler looks up `check_for_type` and doesn't find
    // an overload that can be called with just one explicit type parameter.
    return check_for_type<X>(tail(t));
}

【讨论】:

    猜你喜欢
    • 2017-04-01
    • 2016-10-13
    • 2021-07-31
    • 2017-01-08
    • 2017-11-24
    • 2011-08-19
    • 1970-01-01
    相关资源
    最近更新 更多