Reputation: 506847
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:
Template
(i.e Template<int>
) in the global namespace.Template<float>
in the global namespace. 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
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
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
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
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