【问题标题】:static assert that template typename T is NOT complete? [duplicate]静态断言模板类型名 T 不完整? [复制]
【发布时间】:2014-11-05 21:57:30
【问题描述】:

有没有办法 static_assert 类型 T Not 在标头中的那个点是完整的?这个想法是如果有人在不应该的地方添加#includes,就会产生编译错误。

相关:How to write `is_complete` template?

使用该链接的答案,

namespace
{
template<class T, int discriminator>
struct is_complete {
  static T & getT();
  static char (& pass(T))[2];
  static char pass(...);
  static const bool value = sizeof(pass(getT()))==2;
};
}
#define IS_COMPLETE(X) is_complete<X,__COUNTER__>::value
class GType;
static_assert(!IS_COMPLETE(GType),"no cheating!");

不幸的是,这给出了“invalid use of incomlete type”错误,哦。有没有办法断言否定?

【问题讨论】:

  • 既然你有C++11,你可以使用expression SFINAE
  • @chris:你为什么要在那里介绍declvalcoliru.stacked-crooked.com/a/d2987f9901270a48
  • @Deduplicator,将S 更改为struct S {S(int){}};,您将获得0,只需使用S{} 而不是std::declval&lt;S&gt;()std::declval 为您提供右值引用,因此您无需使用可能存在或不存在的构造函数。但是,是的,一开始这一切都是完全没有必要的,因为我很笨,sizeof 适用于类型。
  • 基于此:clang++ -std=c++1y -stdlib=libc++ -Wall -Wextra -pedantic-errors -O3 -pthread main.cpp /usr/lib/x86_64-linux-gnu/ libstdc++.so.6 && ./a.out #clang++ -E -P main.cpp #g++-4.9 -std=c++1y -Wall -Wextra -pedantic-errors -O3 -pthread main.cpp && ./a .out #clang -xc -std=c11 -Wall -Wextra -pedantic -O3 main.cpp && ./a.out 1 0 从发布的链接来看,即使使用 GCC 4.7x,我似乎也不走运,更不用说VS2012?好的,我将在“将来使用”下提交此文件!

标签: c++ templates static-assert incomplete-type


【解决方案1】:

这是一个使用基于chris proposal 的表达式 SFINAE 的函数,它允许检查类型是否完整。
我的采用不需要包含,当缺少所需的参数时会出错(隐藏参数是不可能的)并且适用于 C++11 以后。

template<typename T>
constexpr auto is_complete(int=0) -> decltype(!sizeof(T)) {
    return true;   
}

template<typename T>
constexpr bool is_complete(...) {return false;}

还有一个测试套件:

struct S;

bool xyz() {return is_complete<S>(0);}

struct S{};

#include <iostream>
int main() {
    std::cout << is_complete<int>(0) << '\n';
    std::cout << xyz() << '\n';
    std::cout << is_complete<S>(0);
}

输出:

1
0
1

See live on coliru

【讨论】:

  • 当然也可以只做一个包装器:constexpr bool foo() {return is_complete&lt;T&gt;(0);}。 C++14 将其简化为变量模板。
  • @chris:试过了,但不知何故,第二次调用等于第一次......
  • @MarcGlisse:我不认为这违反了 ODR,表达式-SFINAE 仅用于选择适当的重载。
  • constexpr 100% 是必要的吗?如果它可以在 Visual Studio 2012 中构建,那就太好了,我正试图防止违反促使在此处放置编译器错误的概念。
  • 我不认为它们在这个解决方案中是可选的......当然,除非你不需要编译时常量表达式。
【解决方案2】:

通过... 传递引用不起作用。

5.2.2/7:

当给定参数没有参数时,参数以这样一种方式传递,即接收方 函数可以通过调用va_arg (18.10) 来获取参数的值。 [注意跳过 - n.m.] 左值到右值 (4.1)、数组到指针 (4.2) 和 函数到指针 (4.3) 标准转换是在参数表达式上执行的。一个论点 有(可能是cv-qualified)类型std::nullptr_t 被转换为类型void* (4.10)。在这些转换之后, 如果参数没有算术、枚举、指针、指向成员的指针或类类型,则 程序格式不正确。

这是根据@chris 的评论匆忙改编的一种可行的解决方案:

#include <iostream>
#include <utility>
namespace
{

    template<typename T, int>
        constexpr auto is_complete(int) -> decltype(sizeof(T),bool{}) {
            return true;
        }

    template<typename T, int>
        constexpr auto is_complete(...) -> bool {
            return false;
        }
}


#define IS_COMPLETE(T) is_complete<T,__LINE__>(0) // or use __COUNTER__ if supported

struct S;

static_assert(IS_COMPLETE(int), "oops 1!");
static_assert(!IS_COMPLETE(S), "oops 2!");

struct S {};

static_assert(IS_COMPLETE(S), "oops 3!");

【讨论】:

  • gcc 4.7.2 出现错误:static_assert(!IS_COMPLETE(S), "oops 2!");
  • 你用什么编译器+标志在本地尝试?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-27
  • 1970-01-01
  • 2016-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多