Using clause on template class - templates

To make referencing types easier you can bring individual types into the current scope with the using clause:
namespace MyCompany
{
namespace MyProject
{
class MyType {};
void myFunc(MyType const& obj) {}
}
}
int main()
{
using MyCompany::MyProject::MyType;
using MyCompany::MyProject::myFunc;
MyType plop;
myFunc(plop);
}
The problem is if the class is a template class (or function). Is it possible to bring these into the current scope without fully instantiating them?
namespace MyCompany
{
namespace MyProject
{
template<typename T>
class MyType {};
template<typename T>
void myFunc(MyType<T> const& obj) {}
}
}
int main()
{
// Can I bring the templates into scope?
// Or do I need to fully instantiate each version in the using clause?
using MyCompany::MyProject::MyType; ????
using MyCompany::MyProject::myFunc; ????
MyType plop;
myFunc(plop);
}

Both VC10 & gcc run the code ok with different instantiations after the using declaration.
So it seems the using declaration has brought the whole template to the scope.
Also in c++0x standard n3290 7.3.3 - 5
A using-declaration shall not name a template-id. [ Example:
struct A {
template <class T> void f(T);
template <class T> struct X { };
};
struct B : A {
using A::f<double>; // ill-formed
using A::X<int>; // ill-formed
};
which seems to suggest that using should not be used with specific template-id.

Related

Making a class template declared in an outer anonymous namespace a friend

Clang refuses to compile the following code (godbolt) while gcc sees no problem with it. Clang error message is shown below line marked (2):
namespace // Overall anonymous namespace is required and cannot be removed.
{
template <typename T>
struct Friend;
namespace ns
{
class Secret
{
template <typename T>
friend struct Friend; // (1)
static void foo() {}
};
} // namespace ns
template <typename T>
struct Friend
{
void bar()
{
ns::Secret::foo(); // (2)
// Error at line (2):
// 'foo' is a private member of '(anonymous namespace)::ns::Secret'
}
};
} // anonymous namespace
The reason, I assume, is that line (1) is treated as a declaration of a new class template struct ns::Friend<T> rather than a reference to ::(anonymous namespace)::Friend<T>.
The questions are:
Who's right -- clang or gcc?
If clang is right, then is there a way to make it understand that line (1) doesn't introduce new class template, but refers to existing one?
Yes, you are right that simply friend struct Friend is a declaration of a templated class ::(anonymous namespace)::ns::Friend. Both compilers are right, as when you attempt to use Friend<T>::bar() gcc will complain about access as well (clang just checks a lot earlier than gcc)
To specify the class template in the global namespace, you must write that out:
template <typename T>
friend struct ::Friend; // (1)
This works for GCC, but clang seems broken and doesn't find Friend in the global namespace.
These two workarounds seem to work:
// Make the entire unnamed namespace an inline namespace
inline namespace
{
// ...
}
// Add an explicit using directive to help clang find Friend in `::`
namespace {
template<typename T>
struct Friend;
}
using ::Friend;
namespace {
namespace ns {
// ...
}
}

Template specialization within namespace

I was messing around with some code when this weird behavior occurred :
In the first test, base templated function, user and templated specialization lie within the same namespace and it behaves as I expect :
namespace Test1
{
template <typename V, typename T>
int doFoo(V& a_visitor, T& a_value)
{
return 0;
}
struct Foo
{
template <typename T>
int process(T const& a_value)
{
return doFoo(*this, a_value);
}
};
template <typename T>
int doFoo(Foo& a_vis, T const& a_ptr)
{
return 1;
}
}
int main()
{
int const k{ 42 };
return Test1::Foo{}.process(k); // returns 1
}
but when I move base templated function and its specialization in another namespace, the base one is selected :
namespace Test2
{
namespace b
{
template <typename V, typename T>
int doBar(V& a_visitor, T& a_value)
{
return 0;
}
}
struct Bar
{
template <typename T>
int process(T const& a_value)
{
return b::doBar(*this, a_value);
}
};
namespace b
{
template <typename T>
int doBar(Bar& a_vis, T const& a_ptr)
{
return 1;
}
}
}
int main()
{
int const k{ 17 };
return Test2::Bar{}.process(k); // returns 0
}
EDIT I can do even weirder : in example 1 if I replace call to doFoo with Test1::doFoo I get the wrong behavior again !
Could anyone explain me what is going on here ? How can I do if I really need struct Bar not to be within namespace b ?
To begin with, those aren't specializations, those are overloads. Completely different function templates that aren't related to each other.
The behavior you see is consistent with argument-dependent lookup. When encountering an unqualified function call, the compiler builds an overload set by examining the namespaces associated with each argument to the function call.
Normally this won't find declarations the come "after", but templates are special. In templates lookup for a dependent name, such as a function call that depends on a template parameter (the type of a_value), is performed after the template is instantiated, and not at the point of definition. That occurs in main, after the namespace is complete and all overloads are available, and so ADL finds the second overload.
This is also why when you qualify the call by Test1 you no longer find the second overload. That negates ADL, and only allows for overloads that appear prior to the point of the call. The easiest way to resolve it would probably be to delay the definition of process until all overloads are available, as other answers indicate.

C++: cannot define member function

Could you please advise why I am getting the error in the code below?
error: cannot define member function ‘Test<int>::Printer::Print’ within ‘Test<int>’
I am using gcc version 8.1.1 and compile the code as g++ -std=c++11.
Although, if I move the definition of function Print under the definition of struct Printer (i.e. making it inline implicitly), the compiler does not produce any error.
#include <iostream>
template <typename Type>
struct TestBase {
struct Printer {
template <typename T>
void Print(const T& t) {
std::cout << t << std::endl;
}
};
};
template <typename Type>
struct Test;
template<>
struct Test<int> : public TestBase<int> {
struct Printer : public TestBase<int>::Printer {
template <typename T>
void Print(int i, const T& t);
};
template <typename T>
void Printer::Print(int i, const T& t) {
std::cout << i << t << std::endl;
}
};
int main() {
Test<int> t;
}
UPDATE:
Brian pointed out the exact reason why it is the case: "... A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition..."
Brian not only answered the main question that started this topic but also an additional question that I asked in the comment to the accepted answer of him.
[class.mfct]/1, emphasis mine:
... A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition. ...
An enclosing class scope is thus not an allowed location for the definition.

Dynamic namespace usage based on a template parameter

I don't know if that is feasable at all, but this is what I'd like to achieve : in a templated class I would like to be using the namespace of the template parameter.
eg.
template<class P>
class Foo
{
public:
Foo();
virtual ~Foo();
void doSomething(P&);
void doSomethingElse();
protected:
// There I'm hardcoding "namespace1" but that's what I'd like to
// be possibly dynamic
// (I'm assuming template parameter P = namespace1::Type)
void method1(namespace1::Type1&);
...
void methodN(namespace1::TypeN&);
}
// Again, supposing P == namespace1::Type then I want to be using namespace1
// everywhere in the implementation...
using namespace namespace1;
template<class P>
void Foo<P>::doSomething(P& parameter)
{
...
Type1 type1 = P.getType1(); // There namespace1::Type1 is returned !!
method1(type1);
...
}
template<class P>
void Foo<P>::doSomethingElse()
{
...
TypeN typen; // There I want to instanciate a namespace1::TypeN !!
...
}
...
Of course I don't want to specialize the template and provide a dedicated implementation for every possible P value as well as I'd like to avoid passing all the types like Type1 and TypeN as template parameters since I potentially have lots of them.
Is that possible ?
The project is C++3 based, any boost solution is welcome.
Update
Being the template parameter P itself exactly like any TypeN parameter, this could be the right approach :
template<typename NAMESPACE>
class Foo
{
typedef typename NAMESPACE::Parameter MyParameter;
typedef typename NAMESPACE::Type1 MyType1;
typedef typename NAMESPACE::Type1 MyTypeN;
...
}
Yes and No.
Yes it is possible to deduce secondary types from a primary one, generally using a trait system:
template <typename T> struct Trait { typedef typename T::Secondary Secondary; };
template <typename X>
struct Foo {
typedef typename Trait<X>::Secondary Secondary;
void foo(Secondary const& s);
};
No, you cannot deduce a namespace, and thus cannot use it; but note how by using a local alias (typedef ...) within the class there is no need to.
If you are willing to add a structure inside each namespace that lists all the types you need, you can then rely on ADL to get this structure depending on a template parameter:
#include <iostream>
#include <utility>
namespace Foo_ns
{
struct T1
{
static void m() { std::cout << "Foo_ns::T1" << '\n'; }
};
struct Foo {};
// List of all the types you need from this namespace
struct Types
{
typedef Foo_ns::T1 T1;
};
// dummy function needed for ADL
Types types(...);
}
namespace Bar_ns
{
struct T1
{
static void m() { std::cout << "Bar_ns::T1" << '\n'; }
};
struct Bar {};
struct Types
{
typedef Bar_ns::T1 T1;
};
Types types(...);
}
template <typename T>
void callMOnT1(const T &arg)
{
typedef decltype(types(std::declval<T>())) Types; // ADL kicks in
//typedef typename std::result_of<types(T)>::type Types;
Types::T1::m();
}
int main()
{
callMOnT1((Bar_ns::Bar())); // Bar_ns::T1
callMOnT1((Foo_ns::Foo())); // Foo_ns::T1
}
Unfortunately, this solution using some C++11 features (namely decltype and declval). For some reason, I didn't manage to get the code working with result_of, which is present in Boost (perhaps someone could explain why the code with result_of does not compile?).
No that is impossible,but you can use ugly macro file.
//my_class.inl
template<TYPE_ARG>
struct my_class_t<TYPE_ARG>
{
foo()
{
NS_ARG::bar();
}
}
//my.h
template<class T>
struct my_class_t{};
#define TYPE_ARG T1
#define NS_ARG std
#include "my_class.inl"
#define TYPE_ARG T2
#define NS_ARG boost
#include "my_class.inl"
#undef TYPE_ARG
#undef NS_ARG
That way you will automate class specialisation for different namespaces. Do you really need this? :o)

C++ template gotchas

just now I had to dig through the website to find out why template class template member function was giving syntax errors:
template<class C> class F00 {
template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here
I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:
f.template bar<T>();
what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?
I got tripped up the first time I inherited a templated class from another templated class:
template<typename T>
class Base {
int a;
};
template<typename T>
class Derived : public Base<T> {
void func() {
a++; // error! 'a' has not been declared
}
};
The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:
template<typename T>
class Derived : public Base<T> {
using Base<T>::a;
void func() {
a++; // OK!
}
};
Alternatively, you can make it explicit that you are using a member of T:
void func {
T::a++; // OK!
}
This one got me upset back then:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write
f.foo::vector<int>();
GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:
"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
template "foo::vector" (declared at line 8) used in preference to
class template "std::vector" (declared at line 163 of
"stl_vector.h")
f.vector<int>(); // ambiguous!
The star of questions about templates here on SO: the missing typename!
template <typename T>
class vector
{
public:
typedef T * iterator;
...
};
template <typename T>
void func()
{
vector<T>::iterator it; // this is not correct!
typename vector<T>::iterator it2; // this is correct.
}
The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.
The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.
template <typename T>
void func()
{
T::staticTemplateFunc<int>(); // ambiguous
T::template staticTemplateFunc<int>(); // ok
T t;
t.memberTemplateFunc<int>(); // ambiguous
t.template memberTemplateFunc<int>(); // ok
}
Out of scope class member function definition:
template <typename T>
class List { // a namespace scope class template
public:
template <typename T2> // a member function template
List (List<T2> const&); // (constructor)
…
};
template <typename T>
template <typename T2>
List<T>::List (List<T2> const& b) // an out-of-class member function
{ // template definition
…
}