Is it possible to make a certain template function have 2 accessibility level for some certain template parameter? (via splitting into 2 functions?)
class B{
enum ENU{
T0,T1,T2
}
template<ENU T=T0> someType f(){ ... } //want T1,T2 = public, T0 = private
};
Current usage (the solution should not change it):-
B b;
int aa=b.f<T0>(); //should fail
std::string bb=b.f<T1>();// should ok
Edit: B has a lot of functions like this.
Here is the full code (just in case someone want to edit or use) https://ideone.com/ryNCml.
I doubt what you are trying to do is possible, as specializing functions on a value ain't allowed in C++.
Though if you don't need enumerations, you could write something similar:
class B {
public:
struct T0{};
struct T1{};
struct T2{};
template<typename T> void f(T, ...) {
static_assert(std::is_same_v<T, T1> || std::is_same_v<T, T2>);
}
private:
void f(T0, ...) {}
};
int main(int argc, char **argv) {
B b{};
b.f(T1{}); // Should compile
b.f(T0{}); // Should not compile
}
If you would use the same function implementation, you can either forward this to a common method, or simply put T0 private.
Alternatively, you could make use of a proxy object which could convert the value, though I'm not sure if this is standard C++ of an extension of the compiler I'm familiar with:
class B {
public:
enum class T { //< Strong typed!
T0,
T1,
T2
}
template <T t>
struct TWrapper {};
template <T ActualT>
void f(..., TWrapper<ActualT> tw = TWrapper<ActualT>{});
private:
template <>
struct TWrapper<T0> {};
}
As far as I can understand, you want to forbid the use of T0 as a template parameter while invoking member method f.
To do that, you can use either std::enable_if or a static_assert.
It follows a minimal, working example:
#include<type_traits>
class B {
public:
enum ENU { T0,T1,T2 };
template<ENU T>
std::enable_if_t<(T==T1||T==T2),int>
f() { return 42; }
template<ENU T>
int g(){
static_assert(T==T1||T==T2, "not allowed");
return 42;
}
};
int main() {
B b;
b.f<B::T1>();
// It doesn't work
//b.f<B::T0>();
b.g<B::T1>();
// It doesn't work
//b.g<B::T0>();
}
Given you want to support only a finite set of template arguments, I would write three functions which are not template functions, and give them the right visibility. Then make them delegate to a private template function which does the work. This would look like:
class B{
public:
enum ENU{
T0,T1,T2
}
private:
template<ENU T=T0> int f(){
std::cout<<"In enum "<<T<<std::endl;
return 0;
}
protected:
someType fT0() { return f<T0>(); }
public:
someType fT1() { return f<T1>(); }
someType fT2() { return f<T2>(); }
};
Contrary to your requirements, the usage changes - but this is often the simplest approach:
B b;
int aa=b.fT0(); // fails
int bb=b.fT1();// ok
Alternatively, you can make the template be public, but give it a dummy argument (with a default), and make the type of the dummy argument depend on the template parameter (via traits). If the type of the dummy is a private class, the template will only be callable by a member.
template <ENU T>
struct protection_traits;
class B{
friend class protection_traits<T0>; // So it has access to Protected.
protected:
struct Protected{};
public:
struct Public{};
enum ENU{
T0,T1,T2
}
template<ENU T=T0> int f( typename protection_traits<T>::type = {})
{ std::cout<<"In enum "<<T<<std::endl; }
};
template <ENU T>
struct protection_traits
{
typedef B::Public type; // Default to public
};
template<>
struct protection_traits<T0>
{
typedef B::Protected type; // But T0 uses Protected
};
Usage:
B b;
int aa=b.f<T0>(); // fails (no access to B::Protected)
int bb=b.f<T1>(); // ok
Note: This latter solution hasn't been fed to a compiler. There will be typos.
Related
I have for following Situation:
template <class K> class A
{
public:
int a;
};
class B
{
public:
virtual void DoSomething() = 0;
};
template <class K> class C : public A<K>, public B
{
public:
virtual void DoSomething()
{
a = 3; // ***
}
};
Now this works on MSVC, however gcc tells me for the line with the 3 stars : "error: 'a' was not declared in this scope". I figured out that I can replace the line with
A::a = 3;
and it works on gcc (well mingw) as well. Do we have to add the original class name all the time to be standard conform? I thought, I only have to add it if names collide otherwise.
I'm using mingw32 (gcc) 4.8.1.
Now it makes sense...
GCC is right, and MSVC is wrong. It should not work because a is template dependent but the expression a; is not.
That is, the meaning you intend of a depends on a template argument (in your case K), but the expression that contains it does not. And since the compiler cannot be sure that the instantiation of A<K> will have a member named a, it simple assumes it does not.
There are several easy solutions, all of them involve using a template dependent expression so resolve a:
this->a = 3; //my favourite
A<K>::a = 3; //you found this one
EXAMPLE:
Let's see an example of why it should not work:
template <typename K> struct A
{
int a;
};
int a; //global variable to make things more interesting
template <typename K> struct B : A<K>
{
void foo()
{
a = 3; //does it refer to A<K>::a or ::a?
}
};
//template specialization of A<int>
template <> struct A<int>
{
};
B<float> bf; // what does bf.foo() do?
B<int> bi; //and bi.foo()?
Also, you can make the opposite situation:
template <typename K> struct A
{
};
int a; //global variable to make things more interesting
template <typename K> struct B : A<K>
{
void foo()
{
a = 3; //does it refer to A<K>::a or ::a?
}
};
//template specialization of A<int>
template <> struct A<int>
{
int a; //now the member variable is in the specialization
};
B<float> bf; // what does bf.foo() do?
B<int> bi; //and bi.foo()?
As you can see, the standard C++ behavior is there for you protection, so that the code you write in a template will always refer -more or less- to the same things:
a: will be always the non template (global in the example) variable, if available. If not, it is a compiler error.
this->a: will be always the member variable, if available. If not, a compiler error.
I have a templated C++ class which has a templated member function as well. The template parameters of this member function are dependent on the class's template parameters in a specific way (please see the code below).
I am instantiating (not specializing) this class for two different values of its template parameter. Everything compiles till this point. However, if I invoke the templated member function, the call for only the first instantiated object compiles and not the second one.
It appears as if the compiler is not instantiating the templated member function for the second instantiation of the template class. I am compiling the code below using "g++ filename.cpp" and am getting the following error:
filename.cpp:63: error: no matching function for call to 'Manager<(Base)1u>::init(Combination<(Base)1u, (Dependent2)0u>*)’
This is the line calling b.init(&combination_2)
g++ --version => g++ (Ubuntu/Linaro 4.4.7-1ubuntu2) 4.4.7
uname -a => Linux 3.2.0-25-generic-pae #40-Ubuntu SMP i686 i686 i386 GNU/Linux
enum Base {
AA,
BB,
CC
};
enum Dependent1 {
PP,
QQ,
RR
};
enum Dependent2 {
XX,
YY,
ZZ
};
template<Base B>
struct DependentProperty {
};
template<>
struct DependentProperty<AA> {
typedef Dependent1 Dependent;
};
template<>
struct DependentProperty<BB> {
typedef Dependent2 Dependent;
};
template <Base B, typename DependentProperty<B>::Dependent D>
class Combination {
public:
void reset() {}
int o;
};
template <Base B>
class Manager {
public:
template <typename DependentProperty<B>::Dependent D,
template<Base,
typename DependentProperty<B>::Dependent> class T>
void init(T<B, D>* t);
};
template <Base B>
template <typename DependentProperty<B>::Dependent D,
template<Base,
typename DependentProperty<B>::Dependent> class T>
void Manager<B>::init(T<B, D>* t) {
t->reset();
}
int main(int argc, char** argv) {
Manager<AA> a;
Manager<BB> b;
Combination<AA, PP> combination_1;
Combination<BB, XX> combination_2;
a.init(&combination_1);
b.init(&combination_2);
return 0;
}
It is not feasible to modify the classes corresponding to Base, Dependent or Combination from my example code in our actual project. What I am really wondering is whether my syntax for defining Manager::init() is wrong, or whether there is some known property/feature/constraint of C++ or g++ that wouldn't allow this code?
The code below compiles for me, I have simplified your code a little, though it still does the same thing.
template <Base B>
class Manager {
public:
typedef typename DependentProperty<B>::Dependent D; // if ever you need it
template <typename TCombinaison>
void init(TCombinaison* t)
{
t->reset();
}
};
int main(int argc, char** argv)
{
typedef Combination<AA, PP> CombinaisonA;
typedef Combination<BB, XX> CombinaisonB;
typedef DependentProperty<AA> DependencyPropertyA;
typedef DependentProperty<BB> DependencyPropertyB;
CombinaisonA combination_1;
CombinaisonB combination_2;
Manager<AA> a;
Manager<BB> b;
a.init(&combination_1);
b.init<&combination_2);
return 0;
}
EDIT: A 2nd solution so as to forbid the mixed use of combination in managers, as the OP has noticed in the comments below. Now I'm using std::is_same to check the "concept" contract.
template <Base B, typename DependentProperty<B>::Dependent D>
class Combination {
public:
typedef typename DependentProperty<B>::Dependent DependencyType;
void reset() {}
int o;
};
template <Base B>
class Manager {
public:
typedef typename DependentProperty<B>::Dependent DependencyType;
template <typename TCombinaison>
void init(TCombinaison* t)
{
static_assert(std::is_same<TCombinaison::DependencyType, Manager::DependencyType>);
t->reset();
}
};
If you combine inheritance and go away from constant template parameters, extend the Combination to provide info on its template arguments, you can get the code to compile taking into account that you don't want this to compile:
b.init(&combination_1);
You are trying very hard to specify and fix the type of the Combination for the init member template within your Manager indirectly, even though the init template will deduce it since it is the only parameter of the function, and the type si defined within main anyway.
Would you consider templating the init directly with the Combination?
This way, everything apart from the init() declaration remains the same, and your code compiles as you wanted to initially:
class Base
{
};
class AA
:
public Base
{
};
class BB
:
public Base
{
};
class Dependent1
{
};
class PP
:
public Dependent1
{};
class Dependent2
{};
class XX
:
public Dependent2
{};
template<class Base>
struct DependentProperty {
};
template<>
struct DependentProperty<AA> {
typedef Dependent1 Dependent;
};
template<>
struct DependentProperty<BB> {
typedef Dependent2 Dependent;
};
template <class Base>
class Combination {
public:
typedef Base CombinationBase;
typedef typename DependentProperty<Base>::Dependent CombinationDependent;
void reset()
{
}
int o;
};
template <class Base>
class Manager
{
public:
// Any type C
template<class C>
void init (C* t)
{
// Any type C conforming to the implicit interface holding reset()
t->reset();
// Forcing specific combination
Base b = typename C::CombinationBase();
// Forcing it again
typename DependentProperty<Base>::Dependent d = typename C::CombinationDependent();
}
};
int main(int argc, char** argv) {
Combination<AA> combination_1;
Manager<AA> a;
a.init(&combination_1);
Manager<BB> b;
Combination<BB> combination_2;
b.init(&combination_2);
b.init(&combination_1);
return 0;
}
In this case, you can extend the Combination template to provide access to its template parameters to the client code. Of course the template C in this case becomes a refinement of the Combination concept as soon as you rely on its implementation within the init member function (accessing the stored template argument values, etc).
Your code is correct, except for the function calling part.
a.init<PP, Combination>( &combination_1 );
b.init<XX, Combination> ( &combination_2 );
This compiles and runs peacefully.
The only thing I see is
template <typename DependentProperty<B>::Dependent D,
template<Base, <-- wrong
typename DependentProperty<B>::Dependent <-- wrong
> class T>
void init(T<B, D>* t);
Your class Combination waits values as a template parameter, but you want to give him types
I spent some time to fix it - like that
template <typename DependentProperty<B>::Dependent D,
template<Base BB,
typename DependentProperty<BB>::Dependent DD
> class T>
void init(T<B, D>* t);
and many other variants, but had no success.
Excuse me for arrange it as an answer, but I couldn't type so many code in a comment
I have a big data member for a class, which is only used for testing:
template <bool testing>
class foo {
int testbuf[1000];
}
How can I make it so? Only when testing is true, include testbuf[]?
Specialize:
template <bool> class foo { };
template <> class foo<true>
{
// everything needed for testing
};
Update: To clarify some points raised in the comments: You would write one such "testing" template per individual item that you want to specialize, so that there's no code duplication. Imagine your real class template is actually bar:
template <bool Testing>
class bar
: private foo<Testing> // specializable base
{
// common stuff
Widget<Testing> widget; // specializable member
Gadget gadget; // unconditional member
};
You can also use composition rather than inheritance; whichever fits best. If you go with inheritance, make sure to spell out this->testbuf.
you can use ifdef stuff
#define DEBUG_MODE
class Foo{
#ifdef DEBUG_MODE
int testbuf[1000];
#else
int testbuf[10];
#endif
}
template <bool testing>
class foo {
}
and
template <>
class foo <true>{
int testbuf[1000];
}
I will assume that testing isn't just used to hold that buff.
template <bool testing>
struct foobuf
{};
template <>
struct foobuf<true>
{
enum {testbuf_size = 1000};
int testbuf[testbuf_size];
foobuf() { std::fill_n( &testbuff[0], testbuf_size, int() ); }
};
template <bool testing>
class foo : public foobuf<testing> {
// ...
};
Going a bit further, you could include a dotest function in foobuf that works like this:
template<bool>
struct foobuf
{
template<typename Func>
void doTest( Func const& unused );
};
template<>
struct foobuf<true>
{
enum {testbuf_size = 1000};
int testbuf[testbuf_size];
foobuf() { std::fill_n( &testbuf[0], testbuf_size, int() ); }
template<typename Func>
void doTest( Func const& f )
{
f( testbuf, testbuf_size );
}
};
which you would use like this within foo:
void foo::some_function(...)
{
// some code
doTest( [&]( int* buf, size_t length )
{
// the code in here only runs if we test was true in foo
// and if so, it has access to the test buff via the buf* parameter
// oh, and it will be almost certainly inlined if test was true in foo
// and thrown away and never created if it was false.
});
}
but that is just me.
Consider the following code :
template<bool AddMembers> class MyClass
{
public:
void myFunction();
template<class = typename std::enable_if<AddMembers>::type> void addedFunction();
protected:
double myVariable;
/* SOMETHING */ addedVariable;
};
In this code, the template parameter AddMembers allow to add a function to the class when it's true. To do that, we use an std::enable_if.
My question is : is the same possible (maybe with a trick) for data members variable ? (in a such way that MyClass<false> will have 1 data member (myVariable) and MyClass<true> will have 2 data members (myVariable and addedVariable) ?
A conditional base class may be used:
struct BaseWithVariable { int addedVariable; };
struct BaseWithoutVariable { };
template <bool AddMembers> class MyClass
: std::conditional<AddMembers, BaseWithVariable, BaseWithoutVariable>::type
{
// etc.
};
First off, your code just won't compile for MyClass<false>. The enable_if trait is useful for deduced arguments, not for class template arguments.
Second, here's how you could control members:
template <bool> struct Members { };
template <> struct Members<true> { int x; };
template <bool B> struct Foo : Members<B>
{
double y;
};
I have a template class, say:
template<class T>
class someClient
{
void someCallbackA() {foo_->onA();}
void someCallbackB() {foo_->onB();}
private:
T* foo_;
};
which I can instantiate with a bunch of different types T which support the onA and onB interface. I happen to have a case where two out of the several different types T I use needs a particular behavior controlled from someClient so I need to add some function doBar() to these two types (call them Edge1 and Edge2). Then I want a part of the someClient code to call foo_->doBar() but without breaking when the type of foo_ does not have that. Is there a way to use boost::enable_if to have a someClient::doBar() which will call foo_->doBar() only for those two types, but not be there, or expand to nothing if the types are not Edge1 or Edge2?
I was thinking along the lines of:
template <class T, enable_if<mpl_or<is_same<T,Edge1>, is_same<T,Edge2> > >
someClient<T>::doBar() {foo_->doBar();}
You don't need to pull any special tricks at all if you just don't call member functions that don't make sense. Template member functions are only specialized when needed (unless you add an explicit specialization). So the following code works fine:
template <typename T> struct Foo
{
void do_foo() { p->foo(); }
void do_bar() { p->bar(); }
T * p;
};
struct A { void foo() {} };
int main()
{
A a;
Foo<A> x = { &a };
x.do_foo();
}
The fact that Foo<A>::do_bar wouldn't compile is not an issue, since the member function is never instantiated. And p->bar isn't a compiler error, because p has a dependent type and the line is thus only parsed in the second lookup phase (which never happens).
I think this does what you want. I used C++11 <type_traits> instead of boost's:
struct Edge {
void doBar() { std::cout << "did Bar."; }
};
template<typename T>
class someClient
{
public:
template<typename U = T>
typename
std::enable_if<std::is_same<U, Edge>::value, void>::type
doBar() { foo_->doBar(); }
template<typename U = T>
void doBar( typename std::enable_if<!std::is_same<U, Edge>::value, void>::type* = 0 )
{ /* do nothing */ }
private:
T* foo_;
};
int main()
{
someClient<int> i;
someClient<Edge> e;
i.doBar();
e.doBar(); // outputs "did Bar."
}
doBar() needs to be template itself for this to work, explanation here: std::enable_if to conditionally compile a member function