C++ C++;需要特定参数包大小的模板概念

C++ C++;需要特定参数包大小的模板概念,c++,c++20,c++-concepts,C++,C++20,C++ Concepts,编辑:此函数必须逐个检查类型,并返回满足条件或nullptr的任何类型的obj template <typename... Args, typename = std::enable_if_t<(sizeof...(Args) == 0)>()> std::nullptr_t f() { return nullptr; } template <typename T, typename... Args> BaseClassOfAllArgs* f() {

编辑:此函数必须逐个检查类型,并返回满足条件或nullptr的任何类型的obj

template <typename... Args, typename = std::enable_if_t<(sizeof...(Args) == 0)>()>
std::nullptr_t f() { return nullptr; }

template <typename T, typename... Args>
BaseClassOfAllArgs* f() {
    if (<some condition related to T...>)
        return new T;
    return f<Args...>();
}
模板
std::nullptr_t f(){return nullptr;}
模板
BaseClassOfAllArgs*f(){
如果()
返回新的T;
返回f();
}
这个代码对我有用。但我想知道是否有可能重写这段代码来使用这个概念? 我的意思是这样的:

template <typename... Args>
concept NoArgs = (sizeof...(Args) == 0);
模板
概念NoArgs=(sizeof…(Args)==0);
然后使用它而不是std::enable_if(此代码不起作用)

模板
std::nullptr_t f(){return nullptr;}
模板
BaseClassOfAllArgs*f(){
如果()
返回新的T;
返回f();
}
编辑:下面是从中获取一些技巧后的代码工作示例 评论里的人。在我将“Base”添加到模板后,结果证明不再需要EmptyPack概念。第一个模板自然需要3个类型名。然而,我不确定这个概念是否是空的。这真的使我的程序格式不正确吗?不需要诊断

#include <iostream>
#include <type_traits>
#include <typeinfo>
class X {};

class A : public X {};
class B : public X {};
class C : public X {};
class D : public C {};
class E {};

template<class T, class... Args >
concept DerivedsOfBase = (std::is_base_of_v<T, Args> && ...);

template<typename... Args>
concept EmptyPack = sizeof...(Args) == 0;

template<typename T>
std::nullptr_t f() {
    std::cout << "End of the types list" << std::endl;
    return nullptr;
}

template<typename Base, typename T, typename... Args> requires DerivedsOfBase<Base, T, Args...>
Base* f() {
    std::cout << typeid(T).name() << std::endl;
    if (<some condition related to T>)
        return new T;
    return f<Base, Args...>();
}

int main()
{
    auto ptr = f<X, A, B, C>();
    auto ptr2 = f<X, A, B, D>();
    //auto ptr3 = f<X, A, B, E>(); // compile error
    return 0;
}
#包括
#包括
#包括
类X{};
A类:公共X{};
B类:公共X{};
C类:公共X{};
D类:公共C{};
E类{};
模板
概念派生sofbase=(std::is_base_of_v&…);
模板
概念EmptyPack=sizeof…(Args)==0;
模板
std::nullptr_t f(){

std::cout任何模板参数包,如果只对大小为0的包进行有效实例化,则会导致程序格式错误,无需诊断

这适用于您的第一个“工作”示例,以及我可以想到的使用概念的任何实际变体

从[temp.res]14.6/8开始:

如果可变模板的每个有效专门化都需要一个空的模板参数包,则该模板的格式不正确,不需要诊断

(我在许多版本的C++中看到过,我只是使用随机草案标准,当我在Google C++标准PDF中出现时)。

注意:(a)你的两个代码< F/COD>是重载而不是专门化,和(b)C++程序员所指的“模板的有效专门化”和标准的含义不是完全相同的。 本质上,几乎任何对您的概念的尝试都会导致格式错误、无需诊断的程序

要了解这里的问题,我们将使用否定改写标准:

如果(变量模板的每个有效专门化都需要一个空的模板参数包),则(模板格式错误,不需要诊断)

我们可以将这个“forall”转换为“there exists”。“forall X,p(X)”与“Not(there exists X,Not p(X))”相同

除非(存在具有非空模板参数包的变量模板的有效专门化),否则(模板格式错误,无需诊断)

如果可变模板具有强制可变模板包为空的requires子句,则不存在具有空参数包的该模板的有效专门化。因此,您的模板格式错误,不需要诊断


一般来说,这些规则的存在是为了让编译器能够检查您的代码是否总是无意义的。诸如没有类型参数可以使其编译的模板,或必须为空的包,通常都是代码存在错误的标志。通过使其格式错误且不需要诊断,编译器可以发出诊断码编译失败

我对该标准的一个问题是,它不仅被允许无法编译,而且被允许编译一个可以做任何事情的程序

因为编译器是允许这样做的,而在其他情况下的一些优化实际上会导致这种情况的发生,所以您应该避免编写格式错误、不需要诊断的代码,比如瘟疫


解决办法是:

namespace implementation_details {
  struct never_use_me;
}
template <class=implementation_details::never_use_me>
std::nullptr_t f() { return nullptr; }

template <typename T, typename... Args>
T* f() {
  if (<some condition related to T...>)
    return new T;
  return f<Args...>();
}
名称空间实现\u详细信息{
结构永远不用我;
}
模板
std::nullptr_t f(){return nullptr;}
模板
T*f(){
如果()
返回新的T;
返回f();
}
另一个选择是:

template <typename T, typename... Args>
T* f() {
  if (<some condition related to T...>)
    return new T;
  if constexpr (sizeof...(Args)==0)
    return nullptr;
  else
    return f<Args...>();
}
模板
T*f(){
如果()
返回新的T;
如果constexpr(sizeof…(Args)==0)
返回空ptr;
其他的
返回f();
}

任何只对大小为0的包进行有效实例化的模板参数包都会导致程序格式错误,无需诊断

这适用于您的第一个“工作”示例,以及我可以想到的使用概念的任何实际变体

从[temp.res]14.6/8开始:

如果可变模板的每个有效专门化都需要一个空的模板参数包,则该模板的格式不正确,不需要诊断

(我在许多版本的C++中看到过,我只是使用随机草案标准,当我在Google C++标准PDF中出现时)。

注意:(a)你的两个代码< F/COD>是重载而不是专门化,和(b)C++程序员所指的“模板的有效专门化”和标准的含义不是完全相同的。 本质上,几乎任何对您的概念的尝试都会导致格式错误、无需诊断的程序

要了解这里的问题,我们将使用否定改写标准:

如果(变量模板的每个有效专门化都需要一个空的模板参数包),则(模板格式错误,不需要诊断)

我们可以将这个“forall”转换为“there exists”。“forall X,p(X)”与“Not(there exists X,Not p(X))”相同

除非(存在具有非空模板参数包的变量模板的有效专门化),否则(模板格式错误,无需诊断)

如果可变模板具有强制可变模板包为空的requires子句,则不存在具有空参数包的该模板的有效专门化。因此,您的模板格式错误,不需要诊断


一般来说,这类ru
template <typename T, typename... Args>
T* f() {
  if (<some condition related to T...>)
    return new T;
  if constexpr (sizeof...(Args)==0)
    return nullptr;
  else
    return f<Args...>();
}
T* f() {
    if constexpr (sizeof...(Args) != 0) {
        if (<some condition related to T...>)
            return new T;
        return f<Args...>();
    } else {
        return nullptr;
    }
}
template <typename T> // no pack
T* f() {
    return nullptr;
}

template <typename T, typename Arg1, typename... Args> // one of more Args
T* f() {
    if (<some condition related to T...>)
        return new T;
    return f<Arg1, Args...>();
}
template <typename T, typename...> // pack logically always empty
T* f() {
    return nullptr;
}

template <typename T, typename... Args> requires (sizeof...(Args) > 0)
T* f() {
    if (<some condition related to T...>)
        return new T;
    return f<Args...>();
}
template<typename... Args>
concept nonempty_pack = sizeof...(Args) > 0;

template <typename T, typename...> // pack logically always empty
T* f() {
    return nullptr;
}

template <typename T, typename... Args> requires nonempty_pack<Args...>
T* f() {
    if (<some condition related to T...>)
        return new T;
    return f<Args...>();
}