是否有任何简单类型,可以保证其大小(sizeof)大于1?

3
当编写通用代码时,我经常需要一个简单的类型T,保证sizeof(T) > 1
例如:
template <typename T>
char test_foo(...);
template <typename T,
    typename = std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::foo)>>>
??? test_foo(int);
template <typename T>
struct has_foo : std::bool_constant<sizeof(test_foo<T>(0))!=1> {};

我有几个选项,但都不是理想的:

  • long long: 不起作用,详见这里
  • struct SizeNot1 { char dummy[2]; };: 必须提前定义,有点烦人
  • char (&test_foo())[2];: 太丑陋了
  • std::array<char, 2>: 它的大小是否保证?

有任何想法吗?


2
我认为你已经基本回答了自己的问题。在任何合理的架构上,long long都足够好,如果你需要标准的绝对保证,那么char (&test_foo())[2]就可以了。它可以被typedef成一个更漂亮的名称,然后你就有了解决方案。我相信任何[语言律师]的解决方案都至少和这个一样丑陋。 - Silvio Mayolo
@JeremyFriesner 你确定吗?因为char不保证有8位。 - Slava
@Slava 这又是一个非常令人困惑的问题: https://www.reddit.com/r/cpp/comments/d9pzwe/guarantees_on_stdarray_inmemory_layout/ - zwhconst
2
@Someprogrammerdude,shortlonglong long 都可以是 1 字节。唯一的保证是sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long) - phuclv
@phuclv 好吧,我承认失败了,我犯了一个常见的错误,把一个字节等同于一个八位组。 - Some programmer dude
显示剩余14条评论
4个回答

4
在编写通用代码时,我经常希望有一个简单的类型T,其保证“sizeof(T)>1”。
我认为你这么做是“错误”的。
对于您的示例,您可以直接使用std::true_type/std::false_type。
template <typename>
std::false_type test_foo(...);

template <typename T, std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::foo)>, int> = 0>
std::true_type test_foo(int);

template <typename T>
using has_foo = deltype(test_foo<T>(0));

如果需要在类型中使用不同的编译时数字,std :: integral_constant可能会有所帮助:

template <typename>
std::integral_constant<std::size_t, 0> test_foo(...);

template <typename T, std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::foo)>, int> = 0>
std::integral_constant<std::size_t, 42> test_foo(int);

template <typename T>
using has_foo = std::bool_constant<deltype(test_foo<T>(0))() == 42>;

char (&test_foo())[2];: 太丑了

有更好看的备选语法:

auto test_foo() -> char(&)[2];

但在我看来,使用typedef会更易读:

template <std::size_t N>
using c_char_array = char[N];

然后

c_char_array<2>& test_foo();

2

我突然想到这应该可以工作:

std::aligned_storage_t<2> & test_foo(int);

这并不引入新的名称,而且相当易读。


实际上,这似乎 不起作用 - cigien
@cigien 它为什么不工作?它输出了16,大于1。 - zwhconst
啊,我不确定为什么我把问题理解成了要求恰好为2个。所以decltype("42")可以工作。我仍然不确定这个解决方案是否保证可行,但这是另一个问题。 - cigien
1
@cigien 如此处所述,std::aligned_storage_t<Len>是至少大小为Len的POD类型,因此sizeof(it) >= 2。不是吗? - zwhconst
哦,是的,看起来没问题。这是一个很好的答案。 - cigien

1

由于 sizeof(char) == 1,因此您可以使用 char[2]。正如您所提到的,其语法为

char (&test_foo())[2];

这段代码可以运行,但可能有些难以理解。

这是一个主观的答案,但我认为

decltype(" ") test_foo();

这段代码相当易读。在这里,我们仅使用了类型为char[2]的文字字面量的类型。


1
使用 char2 = char[2]; 可能会使它稍微好看一些。 - Eljay
@Eljay OP提到他们不想事先声明类型,我猜这意味着避免使用using别名。 - cigien
也许这样更好:decltype("42") test_foo(); ;-) - zwhconst
@zwhconst 如果你想让 sizeof 为3,我肯定会使用它的 :) - cigien
@cigien 我想要 sizeof(T) > 1 - zwhconst
显示剩余2条评论

0

以防萬一。如果您想要創建一個檢測函數存在的模板,可以按照以下方式進行:

#include <iostream>
#include <type_traits>

class A {
public:
    int func() {return 1;}
};

class B {
};

template <typename T, typename = void>
struct has_func : std::false_type {};

template <typename T>
struct has_func<T, std::void_t<decltype(std::declval<T>().func())>>
    : std::true_type {};

template<typename T>
int wrap(T &t) {
    if constexpr (has_func<T>::value) {
        return t.func();
    } else {
        return 0;
    }
}


int main()
{
    A a;
    B b;
    std::cout << "A:" << wrap(a) << ", B:" << wrap(b) << "\n";
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接