【问题标题】:Can a C++ template determine if the instance being declared/defined is constant?C++ 模板能否确定被声明/定义的实例是否为常量?
【发布时间】:2014-01-27 17:11:35
【问题描述】:

对于给定的模板,例如std::string,模板可以检测被声明/定义的string 的实例是否为常量。 (注意:我不是在询问模板参数。)

std::string mutable_string("a string that may possibly be changed");

const std::string immutable_string("a string that will not change);

如果可能,模板可以为提供给构造函数的字符串文字准确分配堆存储量。此外,可以省略非常量、非 ctor/dtor 方法的代码生成(除非某些翻译单元定义了非常量字符串)。

我希望在语义上类似于:

is_constant<std::string>(*this)::value

是否可以将实例的类型与去掉 const 限定符的类型进行比较?

更新/澄清:扩展std::string 示例,const std::string 的模板特化能否将检查员声明为constexpr(例如size()capacity()

【问题讨论】:

  • "对于给定的模板,例如 std::string" std::string 不是模板。 std::basic_string 是。
  • @Manu343726:我想他指的是std::basic_string...无论如何,一个对象永远不能是模板类型,而是模板的实例化,这不再是一个模板。那就是如果你真的想学学。
  • 您可以使用函数来创建可变/不可变字符串:auto mutable_string = make_mutable_string(".."); auto immutable_string = make_immutable_string("..");

标签: c++ templates c++11


【解决方案1】:

如果我猜对了:

#include <iostream>

template <typename T>
inline constexpr bool is_constant(T&) {
    return false;
}

template <typename T>
inline constexpr bool is_constant(const T&) {
    return true;
}

template <bool Value>
void print() {
    std::cout << (Value ? "true " : "false ");
}

struct X {
    void a() { print<is_constant(*this)>(); }
    void b() const { print<is_constant(*this)>(); }
};

int main() {
    X x;
    // false
    x.a();
    // true
    x.b();
    std::cout << '\n';
    return 0;
}

然而,如果你想检测一个对象是否是 const 限定的,那是不可能的——构造函数永远不是 const。

【讨论】:

  • 打算发布类似的内容 +1
  • 我认为问题更多在于构造函数是否可以知道正在构造的实例是否为const。上面的代码将无法检测到这一点,就像在 X 的示例中一样,const-ness 是从隐式 this 参数(函数声明最右边的const)推断出来的,但这不能在构造函数中为const
【解决方案2】:

不,您无法检测正在构造的对象是否将被标记为const。如果您关心的是提供精确的内存分配,那就去做,就可以了。如果字符串不是 const,那么它会在需要时根据需要增长。

关于代码生成,模板的成员通常是按需生成的,所以如果不使用就不会生成,所以没有赢。 通常是因为在显式实例化中不是这种情况,在这种特殊情况下,您的实现可能出于性能原因(编译器时间)进行显式实例化,因为对于basic_string 的常见实例化(char, wchar_t) 供应商可以在链接库中以二进制形式提供已经实现的实现。

【讨论】:

  • 感谢您的回答。不是我希望的答案,但同样感谢你。促使我询问的是我的编译器使用一种算法将缓冲区大小增加 50% 并将旧内容复制到新缓冲区。这是在 ctor 推回提供的文字时迭代完成的。这意味着字符串平均被过度分配了约 25%。在这里提供我自己的分配器将无济于事。我同意您的观点,即省略非常量方法是不成功的。
  • @evangineer:如果任何构造函数过度分配值,您应该向供应商提出问题,如果它们导致发生多次分配,情况会更糟!出于好奇,编译器/版本是什么?
  • @evangineer 从一对迭代器而不是const char* 构造如何? static const char* const foo_ = "a string that will not change"; std::string foo{foo_, foo_ + strlen(foo_)} 可能会导致stringfoo.capacity() == foo.size()。即使是稍微脑残的实现。
  • @casey:试过了(还有很多其他的)。 static const char* const foo_ = "1234567890123456"; std::string foo(foo_, foo_+strlen(foo_)); 在堆上分配 32 个字节,size() == 16capacity() == 31
  • @evangineer IIRC,Visual C++ string 总是分配比 16 的倍数少 1('\0' 终止符空间)的容量,因为它“知道”标准分配器分配内存在 16 字节块中。否则,多余的容量只会因碎片化而丢失。
猜你喜欢
  • 2020-07-09
  • 2020-03-15
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-17
相关资源
最近更新 更多