【问题标题】:How to properly expose underlying template type to be used as type如何正确公开底层模板类型以用作类型
【发布时间】:2020-03-04 12:12:05
【问题描述】:

我有一些字符串类IMyString,它可以是 wstring 或普通字符串。它有两个派生MyStringMWString。如果模板化代码想要同时接受这两者,它当前需要字符串类型参数和字符类型参数。我想改变它。

这是我的代码:

// This string doesn't work, it's just an example
template <typename CharType, typename Derived>
class IMyString
{
public:
  // Define value type so that it can ba accessed by other templates (does not work)
  using ValueType = typename CharType;

  const CharType* c_str() const { return rawData; }
  // Does not actually do the adition for brevity, just imagine it instead
  Derived&& operator+(const CharType* moreData) const { return Derived(/*should add my own data here and also copy everything etc*/moreData); }

protected:
  IMyString(const CharType* rawData) : rawData(rawData) {}

  const CharType* rawData = nullptr;
};

// Normal string
class MyString : public IMyString<char, MyString>
{
public:
  MyString(const char* data) : IMyString(data) {}

};

// Wide char string
class MyWString : public IMyString<wchar_t, MyString>
{
public:
  MyWString(const wchar_t* data) : IMyString(data) {}

};

// Method that doesn't really do anything actually
template <typename StringType>
// I want to be able to use the value type directly as type
void DoSomethingWithAnyString(StringType string, const StringType::ValueType* dataToAdd)
{
  StringType string2 = string + dataToAdd;
  // even if the addition worked, it has no effect because the value is not returned
}

int main()
{
  MyString someString("Hello");
  DoSomethingWithAnyString(someString, " world!");
}

我现在得到的 GCC 错误:

UnderlyingTemplateType.cpp:9:30: error: expected nested-name-specifier before 'CharType'
   using ValueType = typename CharType;

但是当我删除 typename 时,这也是一个错误:

UnderlyingTemplateType.cpp:40:56: error: need 'typename' before 'StringType::ValueType' because 'StringType' is a dependent scope
 void DoSomethingWithAnyString(StringType string, const StringType::ValueType* dataToAdd)

如何正确地做到这一点?我想使用IMyString::ValueType,就像它是一个嵌套类/结构/枚举一样。

我可以看到这是可行的,但我宁愿不要在我使用ValueType 的任何地方写typename

// Method that doesn't really do anything actually
template <typename StringType>
// I want to be able to use the value type directly as type
void DoSomethingWithAnyString(StringType string, const typename StringType::ValueType* dataToAdd)
{
  StringType string2 = string + dataToAdd;
  // even if the addition worked, it has no effect because the value is not returned
}

是否有一个简洁的定义允许ValueType 充当真实类型?

【问题讨论】:

  • 错误告诉你写的是const typename StringType::ValueType* dataToAdd,因为此时StringType对解析器是不透明的。
  • @Quentin 可以通过不同地定义 ValueType 以某种方式避免该要求吗?每次使用都必须写 typename 看起来很烦人,也让人分心,因为它在变量名中并不常见。
  • 否,但您可以定义template &lt;class StringType&gt; using ValueType = typename StringType::ValueType,然后在您的代码中使用ValueType&lt;StringType&gt;
  • 做错误所说的事情...?
  • @TomášZato-ReinstateMonica 在 blockscope 中你可以定义一个新的别名。在您的示例中,您可以使用第二个模板参数typename ValueType = typename StringType::ValueType

标签: c++ c++11 templates using


【解决方案1】:

你能做的最好的事情就是这样 - 编写包装被鄙视的类型名的助手别名。 Live example

template<class T>
using char_t = typename T::ValueType;

// Method that doesn't really do anything actually
template <typename StringType>
// I want to be able to use the value type directly as type
void DoSomethingWithAnyString(StringType string, const char_t<StringType>* dataToAdd)
{
  StringType string2 = string + dataToAdd;
  // even if the addition worked, it has no effect because the value is not returned
}

【讨论】:

  • 我尝试直接在IMyString 中做类似的事情,但我仍然无法使用StringType::char_type。我很困惑为什么有时重复类型名有效而有时无效。
  • @TomášZato-ReinstateMonica 好吧,你只需要接受 so the standard sayeth :P。更严重的是 - 在模板内你不能使用 typename 因为它还不是依赖名称
猜你喜欢
  • 1970-01-01
  • 2019-09-02
  • 2015-06-02
  • 2011-03-03
  • 2021-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多