Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 506847

How to access hidden template in unnamed namespace?

Here is a tricky situation, and i wonder what ways there are to solve it

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

typedef Template<int> Template;

Sadly, the Template typedef interferes with the Template template in the unnamed namespace. When you try to do Template<float> in the global scope, the compiler raises an ambiguity error between the template name and the typedef name.

You don't have control over either the template name or the typedef-name. Now I want to know whether it is possible to:

You are not allowed to add anything to the unnamed namespace. Everything should be done in the global namespace.

This is out of curiosity because i was wondering what tricks there are for solving such an ambiguity. It's not a practical problem i hit during daily programming.

Upvotes: 4

Views: 1671

Answers (4)

Dennis Zickefoose
Dennis Zickefoose

Reputation: 10969

Using 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;
}

With gcc45 that yields

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

Apparently it compiles with Cormeau, but I only have access to their online test, so I'm stuck just assuming it functions as expected.

I couldn't figure out any way to pass an actual type to a struct directly and have it degrade into a template type, but the compiler had no problems stripping the two when it had to guess at function parameters. Maybe this works in C++03 using boost::result_of instead of decltype, but I've never used it before so I figured I'd stick to what I know.

Note the spacing within main. Rebind<::Template, float>::NewType gets gobbled by the parser because of <: being a digraph. I think it gets turned into Rebind[:Template, float>::NewType. So the space before ::Template is vital.

As an aside, I had no idea nested template parameters couldn't use typename [template<template<typename> class T> rather than template<template<typename> typename T>]. I think I relearn that every time I try to remember the syntax for the construct.

Upvotes: 1

Scott Wales
Scott Wales

Reputation: 11686

It's possible to access the global typedefed template by being explicit about the namespace, ie

::Template a

is a Template<int> from the anonymous namespace. Not sure if you can get a Template<float>.

Surprisingly Clang's C++ compiler is fine with the following, probably not standard behaviour:

#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";
}

Upvotes: 0

dash-tom-bang
dash-tom-bang

Reputation: 17843

disclaimer: I don't know why you'd want to do this and would probably speak sternly to someone who did.

namespace
{
   template <typename T> class Template { };
}

typedef Template<int> IntTemplate;
typedef Template<float> FloatTemplate;
typedef IntTemplate Template;

int main() {
    ::Template t;
    FloatTemplate ft;
}

Upvotes: -1

sbi
sbi

Reputation: 224039

I know it somewhat spoils your point, but I really think the main trick is to avoid something like this like the plague.

Upvotes: 1

Related Questions