【问题标题】:How to access hidden template in unnamed namespace?如何访问未命名命名空间中的隐藏模板?
【发布时间】:2010-05-28 21:29:28
【问题描述】:

这是一个棘手的情况,我想知道有什么方法可以解决它

namespace {
  template <class T> 
  struct Template { /* ... */ }; 
}

typedef Template<int> Template;

遗憾的是,Template typedef 会干扰未命名命名空间中的 Template 模板。当您尝试在全局范围内执行 Template&lt;float&gt; 时,编译器会在模板名称和 typedef 名称之间引发歧义错误。

您无法控制模板名称或 typedef 名称。现在我想知道是否有可能:

  • 在全局命名空间中创建类型定义类型为Template(即Template&lt;int&gt;)的对象。
  • 在全局命名空间中创建Template&lt;float&gt; 类型的对象。

不允许向未命名的命名空间添加任何内容。一切都应该在全局命名空间中完成。

这是出于好奇,因为我想知道有什么技巧可以解决这种歧义。这不是我在日常编程中遇到的实际问题。

【问题讨论】:

  • 我将其设为社区 wiki,因为它实际上是一个有趣的好奇问题,而不是实际问题。 :)
  • 请注意,对于第二个问题,至少有一个解决方案可以在所有 clang/gcc/comeau 上编译,但它更难找到 :)跨度>
  • 我没有时间充分考虑这一点,但是分配器不是有一些技巧可以用来更改模板参数吗?你能在这里做类似的事情,并最终得到类似Rebind&lt; ::Template, float&gt;::type 的东西吗?这样,Template 将被重命名,例如 TRebind 中,并且没有歧义。
  • 该死,我会解决这个问题的……需要我的思考帽,我生锈了。

标签: c++ templates names


【解决方案1】:

我知道这在某种程度上破坏了你的观点,但我真的认为主要的技巧是避免像瘟疫这样的事情。

【讨论】:

    【解决方案2】:

    使用 C++0x:

    namespace {
      template<class T> struct Template { };
    }
    typedef Template<int> Template;
    
    #include<iostream>
    
    template<typename T> 
    void PrintType() { 
        std::cout << __PRETTY_FUNCTION__ << std::endl; 
    }
    
    template<typename FullType, typename NewParameter>
    class Rebind {
      template<template<class> class Template, typename OldParameter>
      static Template<NewParameter> function(Template<OldParameter>);
    
    public:
      typedef decltype(function(FullType())) NewType;
    };
    
    int main()
    {
      PrintType< ::Template>();
      PrintType<Rebind< ::Template, float>::NewType>();
      return 0;
    }
    

    使用 gcc45 产生

    void PrintType() [with T = <unnamed>::Template<int>]
    void PrintType() [with T = <unnamed>::Template<float>]
    

    显然它可以使用 Cormeau 编译,但我只能访问他们的在线测试,所以我只能假设它按预期运行。

    我想不出任何方法可以将实际类型直接传递给结构并将其降级为模板类型,但是当编译器必须猜测函数参数时,它可以毫无问题地剥离这两者。也许这在 C++03 中使用 boost::result_of 而不是 decltype 有效,但我以前从未使用过它,所以我想我会坚持我所知道的。

    注意main 内的间距。 Rebind&lt;::Template, float&gt;::NewType 被解析器吞噬,因为 &lt;: 是一个有向图。我认为它变成了Rebind[:Template, float&gt;::NewType。所以::Template前面的空格很重要。

    顺便说一句,我不知道嵌套模板参数不能使用类型名 [template&lt;template&lt;typename&gt; class T&gt; 而不是template&lt;template&lt;typename&gt; typename T&gt;]。我想我每次尝试记住构造的语法时都会重新学习。

    【讨论】:

    • 啊,你的回答让我想到了用 C++03 解决这个问题的第二种方法。实际上,您即将使用第二种方法来解决它... :)
    【解决方案3】:

    可以通过明确命名空间来访问全局类型定义模板,即

    ::Template a
    

    是来自匿名命名空间的 Template&lt;int&gt;。不确定您是否可以得到Template&lt;float&gt;

    令人惊讶的是,Clang 的 C++ 编译器可以很好地执行以下操作,但可能不是标准行为:

    #include <iostream>
    namespace {
        template <class T>
            struct Template {T value;};}
    typedef Template<int> Template;
    
    int main(){    
        ::Template a;
        Template<float> b;
        a.value = 6;
        b.value = 3.14;
        std::cout<<a.value<<" "<<b.value<<"\n";
    }
    

    【讨论】:

    • 是的,clang 接受这一点是不正确的。 Comeau 和 GCC 也禁止这样做 :) 很好的发现,你会报告还是我应该这样做?
    • 既然你是一名语言律师,你能从标准中找到要求将此案视为人为模棱两可的引用吗?你有明确的例子,它不是模棱两可的,编译器有有效和系统的方法来解决它。因此,如果您确实从标准中找到了引用,那么至少尝试针对标准提交错误而不是错误具有有效解决方案的编译器会更合理。
    【解决方案4】:

    免责声明:我不知道您为什么要这样做,并且可能会严厉地对这样做的人说话。

    namespace
    {
       template <typename T> class Template { };
    }
    
    typedef Template<int> IntTemplate;
    typedef Template<float> FloatTemplate;
    typedef IntTemplate Template;
    
    int main() {
        ::Template t;
        FloatTemplate ft;
    }
    

    【讨论】:

    • 嗯,typedef Template&lt;int&gt; Template; 在你的回答中不知何故消失了 :) 它本来是一个块。一切都应该在事后添加。这就是为什么它很难做到:)
    • 哦,我以为要求只是名称空间内的内容不能更改。基本上,无论您尝试做什么都是不正确的。隐藏“内部”事物然后尝试使新旧定义都可用是没有任何意义的。
    • 这完全没有意义。这是一个语言律师的问题。它没有连接到任何有意义的软件:)
    猜你喜欢
    • 2011-02-01
    • 1970-01-01
    • 2018-02-03
    • 2010-12-29
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    • 2018-05-14
    • 1970-01-01
    相关资源
    最近更新 更多