I have two different namespaces that implement identical methods and classes in two different ways. I am writing a class that used this methods and classes to do something, I was wondering if there was a way to declare the namespace without partial specialization as below:
#include <string>
#include <iostream>
namespace one
{
int test()
{
return 1;
}
}
namespace two
{
int test()
{
return 2;
}
}
enum names : int
{
first = 1,
second = 2
};
template <names>
struct base_class;
template <>
struct base_class<names::first>
{
using namespace ::one;
};
template <>
struct base_class<names::second>
{
using namespace ::two;
};
template <names ns>
struct delcare_namespace : public base_class<ns>
{
delcare_namespace()
{
std::cout << test() << "\n";
}
};
for the code above, I get
test’ was not declared in this scope
using namespace is not allowed in class scope, nor is namespace alias. I don't think you can do a specialization that would somehow inject the namespace.
It's not exactly the same, but if it's an option to declare all the functions you need from that namespace in the specialization, you can make the function pointer as a member of that specialization:
template <names>
struct base_class;
template <>
struct base_class<names::first>
{
static constexpr auto test = &one::test;
};
template <>
struct base_class<names::second>
{
static constexpr auto test = &two::test;
};
template <names ns>
struct delcare_namespace : public base_class<ns>
{
delcare_namespace()
{
std::cout << this->test() << "\n";
}
};
I was wondering if there was a way to declare the namespace
Unfortunately, I don't think it's possible inside a class/struct and inheriting it.
is there a work-around for this ?
The best I can imagine (if you can heavily modify your code) is transform your two namespaces in two different classes or structs, so the functions become methods (maybe static methods)
struct baseOne // former namespace one
{
static int test ()
{ return 1; }
};
struct baseTwo // former namespace two
{
static int test ()
{ return 2; }
};
so you can pass the base class (former namespace) as template parameter and inherit from it
template <typename B>
struct foo : public B
{
foo ()
{ std::cout << B::test() << "\n"; }
};
The following is a full working example
#include <string>
#include <iostream>
struct baseOne // former namespace one
{
static int test ()
{ return 1; }
};
struct baseTwo // former namespace two
{
static int test ()
{ return 2; }
};
template <typename B>
struct foo : public B
{
foo ()
{ std::cout << B::test() << "\n"; }
};
int main ()
{
foo<baseOne> f1; // print 1
foo<baseTwo> f2; // print 2
}
If the use of the B:: before the method names is annoying for you, you can transform the static methods inside the bases structs in ordinary methods or add directives as
using B::test;
inside foo.
Related
Initialization of a static variable at the header file by using the templates (Used c++11, the 'inline' approach not supported)
cat base_class.hpp
#include <string>
#ifndef PROGRAM_BASE
#define PROGRAM_BASE
template <typename T>
struct S
{
static std::string s_elfName;
};
template <typename T>
std::string S<T>::s_elfName; //static initialization
class program_base : public S<void>{
public:
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};
#endif
cat base_class.cpp
#include "base_class.hpp"
bool program_base::update_string(){
S<std::string>::s_elfName = "UpdateString";
}
cat read_string.cpp
#include <iostream>
#include "base_class.hpp"
using namespace std;
int main () {
program_base pb; pb.update_string();
cout << program_base::GetElfName() << endl;
}
The above one works fine, When I try to add templet inside the "class program_base"
cat base_class.hpp
#include <string>
#ifndef PROGRAM_BASE
#define PROGRAM_BASE
class program_base {
public:
template <typename T>
struct S
{
static std::string s_elfName;
};
template <typename T>
std::string S<T>::s_elfName; //static initialization
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};
#endif
it's giving an error as " error: member 's_elfName' declared as a template"
Why I'm not able to declare a template inside the class instead of inheriting it?
As stated in the C++ Std. Nested class declaration:
Member functions and static data members of a nested class can be defined in a namespace scope enclosingthe definition of their class.
[Example:
struct enclose {
struct inner {
static int x;
void f(int i);
};
};
int enclose::inner::x = 1;
void enclose::inner::f(int i) { /* ... */ }
— end example]
If you take the definition out of outer class then it should be fine:
template <typename T>
std::string program_base::S<T>::s_elfName;
Since C++17 you can also do inline static initializing:
class program_base {
public:
template <typename T>
struct S
{
inline static std::string s_elfName;
};
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};
Nutshell version: Why can't I define a template specialization (of a std-lib type) that's only useful in the current compilation unit in an anonymous namespace inside that compilation unit / cpp file?
Longer version:
I have a type that's only a quick helper inside one cpp file, let's call it struct Helper. Because it's only used in that compilation unit, it's declared and defined in an anonymous namespace inside the cpp.
Because I want an std::unordered_set<Helper>, I have to specialize std::hash. When I now try to define it inside the same anonymous namespace, I get a C2888 'std::hash<'anonymous-namespace'::Helper>': symbol cannot be defined within namespace 'anonymous-namespace'. Why is that?
I tried adding a using namespace std and similar things inside the AN, too, but to no avail.
/* This doesn't work */
namespace
{
struct Helper
{
int member1;
bool member2;
};
using namespace std;
template<>
struct std::hash<Helper>
{
size_t operator()(const Helper& helper) const
{
return 12345; /* how it's really generated is irrelevant here */
}
};
}
Of course, I can just put the specialization outside the AN, and it works. I just want to understand why it doesn't while it's inside it!
/* This works, but why doesn't the other? */
namespace
{
struct Helper
{
int member1;
bool member2;
};
}
template<>
struct std::hash<Helper>
{
size_t operator()(const Helper& helper) const
{
return 12345; /* how it's really generated is irrelevant here */
}
};
A symbol belonging to namespace std must be defined in a namespace that encloses std which means that you'll have to define it in the global namespace.
Here's an example from C2888:
namespace M {
namespace N {
void f1();
void f2();
}
void N::f1() {} // OK: namspace M encloses N
}
namespace O {
void M::N::f2() {} // C2888 namespace O does not enclose M
}
[temp.expl.spec/9] from the C++20 draft:
A template explicit specialization is in the scope of the namespace in which the template was defined. [ Example:
namespace N {
template<class T> class X { /* ... */ };
template<class T> class Y { /* ... */ };
template<>
class X<int> { /* ... */ }; // OK: specialization in same namespace
template<>
class Y<double>; // forward-declare intent to specialize for double
}
template<>
class N::Y<double> { /* ... */ }; // OK: specialization in enclosing namespace
template<>
class N::Y<short> { /* ... */ }; // OK: specialization in enclosing namespace
— end example ]
The question is rather simple: how to pretty print the name of a template parameter in a C++ class and assign it to a class variable at compile time ?
It seems that both typeinfo (typeid) and boost::typeindex must be evaluated at runtime or as least some part of them. This apparently does not allow the compiler to completely solve a constexpr containing a call to one of this function.
template<typename T>
class X
{
public:
static const char * name = /* SOME C++ code transforming T in a string (either std::string or char */
};
What am I missing ?
Is it only possible to generate a name at runtime ? In that case, does I really need an instantiated object ? It doesn't seem right to me, because the following perfectly work without any instance:
#include <iostream>
#include <string>
#include <boost/type_index.hpp>
using namespace std;
template<class T>
class X
{
public:
static std::string name()
{
return boost::typeindex::type_id<T>().pretty_name();
}
};
struct foobar {};
int main()
{
cout << X<int>::name() << endl;
cout << X<foobar>::name()<< endl;
}
So instead of having name() as a class method, I'd like to have it as a class variable.
I think, it is possible to use custom Type Traits. Please see the next example:
#include <iostream>
#include <string>
using namespace std;
//Using stub type traits
template <class T>
struct TypeTraits;
//your TypeTraits for specific types...
template<>
struct TypeTraits<int>
{
constexpr static const char *name = "int";
};
template<class T>
class X
{
public:
constexpr static const char * name = TypeTraits<T>::name;
};
struct foobar {};
//TypeTraits for custom foobar
template<>
struct TypeTraits<foobar>
{
constexpr static const char *name = "foobar";
};
int main()
{
//Now you can use static member here
cout << X<int>::name << endl;
cout << X<foobar>::name<< endl;
}
Also TypeTraits can be used (and expanded) for other purposes.
the title and the code is self-explanatory,
Is such a thing possible?how?
Is it encouraged? if not, what is the alternative?
thanks
#include <iostream>
using namespace std;
namespace A
{
void foo()
{
cout << "In A\n";
}
}
namespace B
{
void foo()
{
cout << "In B\n";
}
}
template <typename X>
struct Foo {
void foo()
{
X::foo();
}
};
int main()
{
Foo<A> _foo;
_foo.foo();
return 0;
}
You cannot use a namespace as a template type (namespaces are not types); your code does not compile. The best you can hope for is to use Argument Dependent Lookup (ADL), but it won't work for functions taking no parameters.
If you rename your member function, you can find it via ADL by using a proxy tag:
namespace A
{
struct tag {};
void foo(tag)
{
std::cout << "In A\n";
}
}
namespace B
{
struct tag {};
void foo(tag)
{
std::cout << "In B\n";
}
}
template<class Tag>
struct Foo {
void fooADL()
{
foo(Tag{});
}
};
int main()
{
Foo<A::tag> f;
f.fooADL();
}
Is such a thing possible?
No, you can't parametrise a namespace.
if not, what is the alternative?
Use classes, rather than namespaces, to provide parametrisable scopes for the functions:
struct A {
static void foo();
};
struct B {
static void foo();
}
I am trying to figure out if there's any known pattern/idiom in c++ for what I am trying to do here. Class A must be composed of an object that has a function whose argument must also be of type A. The following code doesn't compile since typeid may not be used in a constant expression. Any suggestions?
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
struct B {
int f(T& i) { cout << "Hello\n"; }
};
class A {
B<typeid(A)> b;
};
int main()
{
A k;
}
Your stated requirements don't need templates at all, just a forward declaration:
#include <iostream>
class A; // forward declare A
struct B {
int f(A &i); // declaration only, definition needs the complete type of A
};
class A {
B b;
};
int B::f(A &i) { std::cout << "Hello\n"; } // define f()
int main()
{
A k;
}
You are looking for B<A> b; The following program compiles without error or warning on g++ 4.4.3.
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
struct B {
int f(T& i) { cout << "Hello\n"; return 0; }
};
class A {
public:
B<A> b;
};
int main()
{
A k;
return k.b.f(k);
}
Note: If you are using templates only to avoid forward declaration, my solution is wrong. But, I'll leave it here in case you are using templates for some other legitimate reason.