我可以约束一个C++函数接受一个任意嵌套的特定类型的向量吗?[副本]

rqdpfwrv  于 2023-05-30  发布在  其他
关注(0)|答案(2)|浏览(148)

此问题已在此处有答案

How to get the inner most type of a n-nested vector?(1个答案)
4天前关闭。
我希望能够约束一个C++函数,使它只能接受的参数是:

std::vector<T>
std::vector<std::vector<T>>
std::vector<std::vector<std::vector<T>>>
...

以此类推,接受任意嵌套的std::vector,但具有特定类型T
我想编译以下内容:

template<typename T>
requires IsVectorInt<T>
auto foo(T t)
{

}

int main()
{
    std::vector<int> intvec {1, 2, 3};
    std::vector<std::vector<int>> vecofvec {{1, 2}, {1, 3}};
    foo(intvec);
    foo(vecofvec);
}

到目前为止,我已经成功地限制了一个使用概念的函数只接受以下两种情况之一:
std::vector<T>其中T本身可以是另一个std::vector
或:
std::vector<int>,但不接受任何嵌套向量。
我的代码如下所示:

template<class, template<class...> class>
inline constexpr bool is_specialization = false;

template<template<class...> class T, class... Args>
inline constexpr bool is_specialization<T<Args...>, T> = true;

template<class T>
concept IsVector = is_specialization<T, std::vector>;

template<class T>
concept IsVectorInt = IsVector<T> && std::is_same_v<int, typename T::value_type>;

template<typename T>
requires IsVector<T>
auto foo(T t)
{

}

int main()
{
    std::vector<int> intvec {1, 2, 3};
    std::vector<std::string> vecofstr {"bar", "baz"};
    std::vector<std::vector<int>> vecofvec {{1, 2}, {1, 3}};
    foo(intvec);
    foo(vecofvec);
    foo(vecofstr); // I would like this line to fail to compile

}
polhcujo

polhcujo1#

如果你的目标是检测算术类型的vector或嵌套vector,这里有一个递归实现trait的建议:

#include <iostream>
#include <type_traits>
#include <vector>

template <typename T>
struct NestedVector : public std::false_type {};
template <typename T>
struct NestedVector<std::vector<T>>
    : public std::conditional_t<std::is_arithmetic<T>::value ||
                                    NestedVector<T>::value,
                                std::true_type, std::false_type> {};

// C++<20 version
template <typename T, std::enable_if_t<NestedVector<T>::value, bool> = true>
void foo(T t) {}

// C++20 version
// template <typename T>
// requires NestedVector<T>::value
// void foo(T t) {}

int main() {
    std::vector<int> intvec{1, 2, 3};
    std::vector<std::string> vecofstr{"bar", "baz"};
    std::vector<std::vector<int>> vecofvec{{1, 2}, {1, 3}};
    foo(intvec);
    foo(vecofvec);
    // foo(vecofstr);  // KO
}

(NB:我使用的是C++<20,所以我删除了requires,但我认为它可能工作得一样)Live Demo

cwdobuhd

cwdobuhd2#

您可以简化并使示例***更具可读性***,方法是创建一个trait来查找vector的最内部类型,然后使用static_assert,如下所示:

//trait to get the innermost type 
template <typename T>
struct inner_type
{
    using type = T;
};
//specialization
template <typename T>
struct inner_type<std::vector<T>>
{
    using type = typename inner_type<T>::type;
};
//alias for convenience 
template<typename T>
using inner_type_t = typename inner_type<T>::type;

template<typename T>
auto foo(std::vector<T> t)
{ 
    static_assert(std::is_arithmetic_v<inner_type_t<T>>);
}  
int main()
{
    std::vector<int> intvec {1, 2, 3};
    std::vector<std::vector<int>> vecofvec {{1, 2}, {1, 3}};
    foo(intvec);       //works 
    foo(vecofvec);     //works 

    std::vector<std::string> vecofstr{"bar", "baz"};
    //foo(vecofstr);  //fails as expected
}

Working demo
使用require(或enable_if_t)而不是static_assert平凡的,如下所示:

template<typename T>
auto foo(std::vector<T> t) requires(std::is_arithmetic_v<inner_type_t<T>>)
{ 
}

Demo

相关问题