The following code compiles correctly on g++ (Debian) with 0 warnings:
#include <list>
template <typename T>
struct A
{
T a;
typedef T value_type;
};
template <typename T>
struct B
{
typedef std::list < A <T> > Type;
};
template <typename Data>
void test ( Data d, typename Data::value_type::value_type b ) { }
int main(int argc, char* argv[])
{
B <double> ::Type b;
double c = 0.0;
test <typename B <double>::Type > (b, c);
return 0;
}
However, after VS 2010 compiler used, the following error occured:
Error 1 error C2770: invalid explicit template
argument(s) for 'void test(Data,Data::value_type::{ctor})
Why is the explicit argument not correct?
Updated question
I am not sure if your advice was understood correctly. You mentioned something like this? However, this construction does not make sense to me.
template <typename Data>
void test ( Data d, typename identity <typename Data::value_type>::type::value_type b) { }
The problem here is that your compiler implements a rule that was present in only a pre-C++11 draft and was added there to make inheriting constructors work when the base class is only known via a typedef. Saying using TypedefName::TypedefName; then makes the using declaration refer to the base class constructors (in your case the parameter type is made incorrectly refering to the constructors of A <double>).
The problem was that this handling was active even outside of using declarations. After a defect report noted that, the handling was reduced to only using declarations. So your code is correct and the compiler is wrong.
I know it's an old post but just in case it helps anyone (note the addition of the template keyword in the declaration of the second argument of test():
#include <list>
template <typename T>
struct A
{
T a;
typedef T value_type;
};
template <typename T>
struct B
{
typedef std::list < A <T> > Type;
};
template <typename Data>
void test ( Data d, typename Data::value_type::template value_type b ) { }
int main(int argc, char* argv[])
{
B <double> ::Type b;
double c = 0.0;
test <typename B <double>::Type > (b, c);
return 0;
}
This should compile with VS 2010
Related
The following code:
namespace N {
template <typename A, typename B = A>
class Foo;
}
template <typename C, typename D>
class N::Foo {
public:
Foo() = default;
};
int main()
{
N::Foo<char> foo;
}
involves a (forward) declaration of the class template Foo inside namespace N
with two type parameters (A and B). The (forward) declaration gives the second parameter a default value which is identical to the first parameter (A). Later, this class is defined with its parameters differently named (C and D). Since it is already specified, the default is not given.
This compiles in GCC 7.1 and Clang 3.8 (in C++17 mode) except that the unused variable foo is warned. However, VS 2017 15.7.5 (in C++17 mode) says A is undefined identifier, and says it is not a valid type name for parameter D.
To my surprise, when I changed the code into this:
namespace N {
template <typename A, typename B = C> //note: A changed into C
class Foo;
}
template <typename C, typename D>
class N::Foo {
public:
Foo() = default;
};
int main()
{
N::Foo<char> foo;
}
VS accepts it! (It does not compile in GCC or Clang, though)
I think VS is wrong here. It tries to interpret the default argument in a different context (in this specific case, the definition of Foo) whereas GCC and Clang don't. At which step was I wrong? Or is this a bug of VS?
Any help will be appreciated.
(Sorry for my bad English)
I would say that this is definitely a compiler bug. Using the name of a previous template parameter in the default argument of a subsequent parameter is common practice, the standard library itself does it all over the place (e.g., allocators and comparison functions for standard containers). The standard even explicitly mentions this possibility in a note in [basic.scope.temp] §3.
VS 2015 seems to be affected too. Note that the template doesn't even have to be in another namespace. I stripped down your example a bit further:
template <typename A, typename B = A>
struct S;
template <typename C, typename D>
struct S {};
int main()
{
S<int> s;
}
and this seems to already trigger the issue…
Try this.
namespace N {
template <typename A, typename B = A>
class Foo;
}
template <typename A, typename B> //A and B is TYPE
class N::Foo {
public:
Foo() = default;
};
int main()
{
N::Foo<char> foo;
}
You can check the reason in the webpage:https://learn.microsoft.com/en-us/cpp/cpp/templates-cpp
T is a template parameter; the typename keyword says that this
parameter is a placeholder for a type. When the function is called,
the compiler will replace every instance of T with the concrete type
argument that is either specified by the user or deduced by the
compiler.
For example, it must be an error if you write a code like:
double example(double,int);
int main()
{
//...
}
double example(double a,double b)
{
//...
}
because the TYPE you specified conflicts with the prototype.
(Sorry for my poor English)
Consider the following code, in C++11, tested with g++-6, g++-7, clang++-3.8 and clang++-4.0
// Preamble
#include <iostream>
// Base 0
template <class T, template <class, T...> class Derived>
struct base0 {
void operator=(int) {std::cout << "base0::operator=\n";}
};
// Base 1
template <class T, int N, template <class, T...> class Derived>
struct base1 {
void operator=(int) {std::cout << "base1::operator=\n";}
};
// Derived 0
template <class T, int N>
struct derived0: base0<int, derived0> {
using base0::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = SUCCESS
using base0<int, derived0>::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = ERROR
};
// Derived 1
template <class T, int N>
struct derived1: base1<int, N, derived1> {
using base1::operator=; // g++6/7 = ERROR, clang++-3.8/4.0 = ERROR
using base1<int, N, derived1>::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = ERROR
};
// Main
int main()
{
derived0<int, 3> object0;
derived1<int, 3> object1;
object0 = 42;
object1 = 42;
return 0;
}
g++ and clang++ do not produce errors with the same version of the using base::operator=. Which one of them is right, and what does the C++ standard say?
This is Clang not implementing DR1004 and hence not allowing the injected-class-name of derived0/1 to be used as a template-name.
GCC's handling of your code appears to be correct in all cases. The difference between 0 and 1 is due to the base being nondependent in 0 but dependent in 1. In the former case name lookup for base0 finds its injected-class-name which can be validly used as a type name. In the latter case, name lookup skips the dependent base and finds the ::base1 template instead.
It appears a forward declaration is causing an issue when specializing some template functions within a template class. I am specializing the class also as it's necessary in order to specialize the function, and this seems to be causing the issue.
Edit: Second question about pre-creating functions for process function:
processor.H
namespace OM{
template<typename MatchT> //fwd decl. ERROR 2. see below.
class Manager;
template<typename MatchT>
class Processor
{
public:
Processor(Manager<MatchT>& mgr_):_manager(mgr_) {}
template<int P>
void process();
void doProcess();
private:
Manager<MatchT>& _manager;
template<int P, int... Ps>
struct table : table<P-1,P-1, Ps... > {};
template<int... Ps>
struct table<0, Ps...>
{
static constexpr void(*tns[])() = {process<Ps>...};
};
static table<5> _table;
};
}
#include "processor.C"
processor.C
namespace OM{
#include "MyManager.H" (includes MyManager/MyConfig)
template<typename MatchT>
template<int P>
inline void Processor<MatchT>::process()
{
...
_manager.send(); //this works..
}
template <> template <>
inline void Processor<MyManager<MyConfig> >::process<1>()
{
_manager.send(); //ERROR 1 - see below.
}
//ERROR here:
template<typename MatchT>
void doProcess()
{
Processor<MatchT>::_table::tns[2](); ERROR 3 below.
}
}
compile errors:
1. error: invalid use of incomplete type 'class Manager <MyManager<MyConfig> >'
2. error: declaration of 'class Manager<MyManager<MyConfig> >'
class Manager;
3. error: no type name '_table' in "class Processor<MyManager<MyConfig> >'
I'm not calling this from a specialized function, so I'm not sure
why I'm getting this.
I can move things around a bit to ensure the _manager calls are not within the specialized functions, but I'd rather not if I don't have to.
I played around with this, I think now I get a similar result.
The problem is the template specialisation and forward declaration together. This should be eqvivalent:
template<typename T> struct A;
template<typename T> class B
{
template<int N>
T f();
};
template<typename T> class B<A<T>>
{
A<T> *a;
template<int N>
T f();
};
template<typename T> struct A{ T i=1; };//works
template<>
template<>
int B<A<int>>::f<1>()
{
return a->i + 1;
}
//template<typename T> struct A { T i = 1; };//error
int main()
{
B<A<int>> b;
}
The compilation for templates comes in two stages:
First, it checks syntax and (some) dependence. So, for example if a in B<A<T>> was not a pointer/reference, but the object itself, it could compile, if that B<A<T>> is constructed after A is defined. (worked for me)
So the second is when the compiler inserts the arguments, here, the compiler must know all objects to generate code.
When fully specialising, as above, the compiler is forced to know all types. It already knows, that f function depends on the implementation of A, so it cannot generate the code.
Therefore you have to define A or Manager before the function specialisation.
I wonder whether it is possible to put the whole code of such a class inside the class (kind of as in Java). I'm doing this for some piece of code, instead of having to search for each function, I'd rather have the whole class on a single sheet of paper (yes, I do print them, I tend to like paper these days).
#include <iostream>
template <class V> class A {
public:
A();
};
template <class V> A<V>::A() {
std::cout<<"Generic"<<std::endl;
}
template <> A<bool>::A() {
std::cout<<"bool"<<std::endl;
}
int main(int argc, char** argv) {
A<int> a;
A<bool> b;
}
Now is it possible to get something along those lines ?
#include <iostream>
template <class V> class A {
public:
A() {
std::cout<<"Generic"<<std::endl;
};
/* somethig specifying specialization for bool */ A() {
std::cout<<"bool"<<std::endl;
}
};
int main(int argc, char** argv) {
A<int> a;
A<bool> b;
}
Is this possible at all ?
Yes, it is possible to have everything in a single class definition without specializations, using std::enable_if to choose the appropriate constructor like this:
template <bool C, typename T = void>
using only_if = typename std::enable_if <C, T>::type;
template <typename A, typename B>
using eq = typename std::is_same <A, B>::type;
template <class V> class A {
public:
template <typename D = int, only_if <!eq <V, bool>{}, D> = 0>
A() { std::cout<<"Generic"<<std::endl; };
template <typename D = int, only_if <eq <V, bool>{}, D> = 0>
A() { std::cout<<"bool"<<std::endl; }
};
where template aliases only_if and eq are just for brevity.
Template parameter D is dummy. Usually we apply enable_if on a template parameter, a function argument, or a return type. A non-template default constructor is a unique exception having nothing of the above, hence the dummy.
This approach is maybe an overkill for this simple example, where a template specialization may be simpler. But a class of 30 lines of code that needs a specialization like that for just one constructor will be definitely simpler this way rather than duplicating all code for the entire class specialization. One may argue that in this case the code may be refactored using a base class that contains only what needs to be specialized. However:
There are also cases where you don't want to choose between two constructor versions, but only to enable or disable a single version according to a type predicate, e.g. whether a type is std::default_constructible or not.
Or, you may need to decide whether a constructor is declared explicit or not, again depending on a type predicate (so, provide an explicit and a non-explicit version).
In such cases, enable_if is very convenient.
Check here an example of a very generic tuple implementation with five constructors, all using enable_if, and one (the default) using a dummy template parameter. The remaining four are for the combinations of explicit vs. non-explicit and element-list vs other-tuple.
Yes.
It is completely possible though the specialization must be done in other template.
#include <iostream>
template <class V> class A {
public:
A() {
std::cout<<"Generic"<<std::endl;
};
};
template <> class A<bool>
{
public:
A() { std::cout << "Bool specialization" << endl; }
};
int main(int argc, char** argv) {
A<int> a;
A<bool> b;
}
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