I want to define a function template of a class template. The code looks like this.
template<int M>
struct test{
private:
int value;
template<int N = 2 * M>
friend auto foo(test const t){
test<N> r;
r.value = t.value;
return r;
}
};
int main(){
test<1> t;
foo(t);// expected to return test<2>
foo<1>(t);// expected to return test<1>
foo<3>(t);// expected to return test<3>
}
But it won't compile. Compared with previous problems, the following lists the differences.
The result of the function template involves another instatiation of the class template. It seems that the function template has to be defined outside. But I am not sure.
The function template uses default template arguments. So, if the function template is defined outside the class, a helper function template is required.
Compiling Errors with g++ -std=c++1z:
a.cpp: In instantiation of 'auto foo(test<M>) [with int N = 2; int M = 1]':
a.cpp:16:10: required from here
a.cpp:4:9: error: 'int test<2>::value' is private
int value;
^
a.cpp:9:17: error: within this context
r.value = t.value;
^
a.cpp: In instantiation of 'auto foo(test<M>) [with int N = 3; int M = 1]':
a.cpp:18:13: required from here
a.cpp:4:9: error: 'int test<3>::value' is private
int value;
^
a.cpp:9:17: error: within this context
r.value = t.value;
^
A possible workaround, yet not correct either.
template<int M>
struct test{
private:
int value;
template<int NA, int NR>
friend test<NR> foo_impl(test<NA> const&);
};
template<int NA, int NR>
test<NR> foo_impl(test<NA> const& t){
test<NR> r;
r.value = t.value;
return r;
}
template<int NR, int NA>
auto foo(test<NA> const& t){
return foo_impl<NA, NR>;
}
template<int NA>
auto foo(test<NA> const& t){
return foo_impl<NA, NA * 2>(t);
}
int main(){
test<1> t;
foo(t);
foo<3>(t);
foo<1>(t);
}
Error:
t.cpp: In function 'int main()':
t.cpp:31:13: error: call of overloaded 'foo(test<1>&)' is ambiguous
foo<1>(t);
^
t.cpp:18:6: note: candidate: auto foo(const test<NR>&) [with int NR = 1; int NA = 1]
auto foo(test<NA> const& t){
^
t.cpp:23:6: note: candidate: auto foo(const test<NA>&) [with int NA = 1]
auto foo(test<NA> const& t){
^
After your edit, one possible way (which may not be better than your workaround - but work for all call) would be to use a default value for the parameter N:
template<int M>
struct test{
private:
int value;
template<int K, int U, int P>
friend test<P> foo(test<U> const t);
};
template <int N = 0, int M, int P = ((N == 0) ? M * 2 : N)>
test<P> foo (test<M> const t) {
test<P> r;
r.value = t.value;
return r;
}
int main(){
test<1> t;
test<2> p1 = foo(t);
test<3> p2 = foo<3>(t);
test<1> p3 = foo<1>(t);
}
This may not be prettier than your version...
The problem here is that you are declaring foo<N> a friend of test<M> while you want it to be a friend of any test<...>. You should do the following:
template<int M>
struct test{
private:
int value;
template<int U, int K>
friend test<K> foo(test<U> const t);
};
template <int M, int N = 2 * M>
test<N> foo (test<M> const t) {
test<N> r;
r.value = t.value;
return r;
}
int main(){
test<1> t;
foo(t);
}
Here you are saying:
Any function test<K> foo<U, K> (test<U> const) is a friend of any test<...>.
Related
I'm struggling to get the below code to compile. I want to enable foo function for class A only when N=3.
#include <iostream>
template <size_t N>
class A
{
public:
template <size_t n = N, std::enable_if_t<(n == 3)>* = nullptr> int foo(int a);
};
template<size_t N>
template <size_t n = N, std::enable_if_t<(n == 3)>* = nullptr>
int A<N>::foo(int a)
{
return a * 4;
}
int main()
{
A<3> a1;
std::cout << a1.foo(10) << std::endl;
// the below should fail to compile
// A<4> a2;
// std::cout << a2.foo(7) << std::endl;
}
Output
<source>:12:20: error: default argument for template parameter for class enclosing 'int A<N>::foo(int)'
12 | int A<N>::foo(int a)
| ^
Whenever you separate a function's declaration and definition, whether it is a template function or not, default argument values can only be in the declaration, not in the definition. So, simply remove the default values from foo's definition, eg:
#include <iostream>
template <size_t N>
class A
{
public:
template <size_t n = N, std::enable_if_t<(n == 3)>* = nullptr> int foo(int a);
};
template<size_t N>
template <size_t n, std::enable_if_t<(n == 3)>*>
int A<N>::foo(int a)
{
return a * 4;
}
Online Demo
I'm trying to make a sum function using variadic template.
#include <iostream>
int sum() {
return 0;
}
template <int first, int ...Rest>
int sum() {
return first + sum<Rest...>();
}
int main() {
sum<1, 2, 3>();
}
But I got an error like this:
test.cc: In instantiation of 'int sum() [with int first = 3; int ...Rest = {}]':
test.cc:10:31: recursively required from 'int sum() [with int first = 2; int ...Rest = {3}]'
test.cc:10:31: required from 'int sum() [with int first = 1; int ...Rest = {2, 3}]'
test.cc:14:17: required from here
test.cc:10:31: error: no matching function for call to 'sum<>()'
return first + sum<Rest...>();
~~~~~~~~~~~~^~
test.cc:9:5: note: candidate: 'template<int first, int ...Rest> int sum()'
int sum() {
^~~
test.cc:9:5: note: template argument deduction/substitution failed:
test.cc:10:31: note: couldn't deduce template parameter 'first'
return first + sum<Rest...>();
so I changed
int sum { return 0; }
to
template<int first>
int sum { return first; }
but I got an another error:
test.cc:11:31: error: call of overloaded 'sum<3>()' is ambiguous
return first + sum<Rest...>();
~~~~~~~~~~~~^~
What should I do?
Your issue here is that sum<Rest...>() when Rest is empty won't call int sum() because that function is not a template.
When you change it to
template<int first>
int sum { return first; }
then the issue becomes that template<int first> int sum and template <int first, int ...Rest> int sum() with Rest being empty resolve to being the same function. There are no rules about a tie break here so you get a compiler error.
The old way to fix this was to just add another template parameter to the variadic template giving you an overload set of
template <int first>
int sum() {
return 0;
}
template <int first, int second, int ...Rest>
int sum() {
return first + sum<second, Rest...>();
}
and with that once Rest is empty the only viable function to call is template <int first> int sum()
Now that we have fold expressions this isn't needed anymore and you can just use
template <int... Vals>
int sum() {
static_assert(sizeof...(Vals) > 0, "You must provide at least one template parameter");
return (... + Vals);
}
In C++17, you might do:
template <int first, int ...Rest>
int sum() {
return (first + ... + Rest);
}
Alternative would be to use class and specialization:
template <int N, int Is...>
struct sum
{
int operator () () const { return N + sum<Is...>{}(); }
};
template <int N>
struct sum<N>
{
int operator () () const { return N; }
};
I have that piece of code (which is a minimal reproduced from a way larger project).
#include <type_traits>
template<typename PA, typename E = void>
struct poly_gcd_reduce_helper;
template<typename PA>
struct poly_gcd_reduce_helper<PA, typename std::enable_if<(PA::sign() > 0)>::type>
{
static constexpr auto val = PA{};
};
template<typename PA>
struct poly_gcd_reduce_helper<PA, typename std::enable_if<(PA::sign() <= 0)>::type>
{
static constexpr auto val = -PA{};
};
template<typename PA, typename PB>
struct poly_gcd
{
static constexpr auto val = poly_gcd<PB, decltype(PA{} -(PA{} / PB{}) * PB {})>::val;
};
template<typename PA>
struct poly_gcd<PA, typename PA::zero_type>
{
static constexpr auto val = poly_gcd_reduce_helper<PA>::val;
};
template<int p>
struct myint{
static constexpr int val = p;
using zero_type = myint<0>;
constexpr int sign() const {
if constexpr (p > 0)
return 1;
else if constexpr (p == 0)
return 0;
else
return -1;
}
constexpr auto operator-() const {
return myint<-p>{};
}
};
template<int a, int b>
static constexpr auto operator/(myint<a> aa, myint<b> bb)
{
return myint<a / b>{};
}
template<int a, int b>
static constexpr auto operator*(myint<a> aa, myint<b> bb)
{
return myint<a * b>{};
}
template<int a, int b>
static constexpr auto operator-(myint<a> aa, myint<b> bb)
{
return myint<a - b>{};
}
template<int a, int b>
static constexpr auto operator+(myint<a> aa, myint<b> bb)
{
return myint<a + b>{};
}
int main() {
constexpr auto zou = poly_gcd<myint<2>, myint<4>>::val;
}
It fails with gcc 9.2 with the following error :
In instantiation of 'constexpr const auto poly_gcd, myint<0>>::val':
recursively required from 'constexpr const auto poly_gcd, myint<2> >::val'
required from 'constexpr const auto poly_gcd, myint<4> >::val'
:70:56: required from here
:27:27: error: incomplete type
'poly_gcd_reduce_helper, void>' used in nested name specifier
static constexpr auto val = poly_gcd_reduce_helper::val;
Apparently the compiler tries to instanciate poly_gcd_reduce_helper, void> even if I have mutually exclusive implementations of poly_gcd_reduce_helper depending on the sign of the first template argument.
I must admit I don't know what to do now.
In the specialization of poly_gcd_reduce_helper, given the usage PA::sign() > 0, sign() is expected to be a static member function; while myint::sign() is a non-static member function. Then for myint the specialization of poly_gcd_reduce_helper would never be selected.
Change it to
static constexpr int sign() {
if constexpr (p > 0)
return 1;
else if constexpr (p == 0)
return 0;
else
return -1;
}
LIVE
There's no need to wrap an integer in a special type, this can all be dramatically simplified:
#include <iostream>
#include <type_traits>
using namespace std;
template<int VA, int VB>
struct poly_gcd {
static constexpr auto val = poly_gcd<VB, VA-(VA/VB)*VB>::val;
};
template<int VA>
struct poly_gcd<VA, 0> {
static constexpr int val = (VA < 0) ? -VA : VA;
};
int main() {
constexpr auto zou = poly_gcd<5,10>::val;
cout << "zou: " << zou << endl;
}
╰─▸ ./test
zou: 2
I'm working on a C++11 wrapper around a C api. The C api offers a bunch of getters for various types, with a different name for each type. Values are retrieved by array of a given size, known at compilation.
I want to give the type and the array size by template, to call the right function.
#include <string>
#include <iostream>
template <typename T>
struct make_stop {
constexpr static bool value = false;
};
class Foo
{
public:
Foo() : i(42) {}
template<typename T, size_t n>
T get();
private:
int i = 0;
};
template<typename T, size_t n>
T Foo::get() { static_assert(make_stop<T>::value); return T(); }
template<int, size_t n>
int Foo::get() { return i + n; }
int main() {
Foo foo;
int i = foo.get<int, 4>();
double f = foo.get<double, 2>();
return 0;
}
But it fails to match the right function
main.cpp:26:5: error: no declaration matches 'int Foo::get()'
int Foo::get() { return i + n; }
^~~
main.cpp:15:7: note: candidate is: 'template<class T, long unsigned int n> T Foo::get()'
T get();
its a bit vauge from your question, but assuming you are wanting to index into some c- arrays and return the value at I you can't specialize function templates like you want, but you can use some tags instead, something like..
class Foo
{
public:
Foo() : is{1,2,3,4,5,6,7,8,9,10},ds{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.1} {}
template <typename T> struct type_c{};
template <size_t I> struct int_c{};
template<typename T,size_t I>
auto get()
{ return get_impl(type_c<T>(),int_c<I>()); }
private:
template <size_t I>
auto get_impl(type_c<int>,int_c<I>)
{ return is[I]; }
template <size_t I>
auto get_impl(type_c<double>,int_c<I>)
{ return ds[I]; }
int is[10];
double ds[10];
};
int main() {
Foo foo;
int i = foo.get<int,0>();
double d = foo.get<double,2>();
std::cout << i << " " << d << std::endl;
return 0;
}
Demo
If I understood you correctly you want to partially specialize get for T. Unfortunately partial specialization for methods is not allowed by the standard. You can however get around this with a static method on a class templated by T and specializing the class.
Like this:
template <class T> struct Foo_helper;
struct Foo
{
Foo() : i{42} {}
template<class T, std::size_t N>
T get()
{
return Foo_helper<T>::template get<N>(*this);
}
int i = 0;
};
template <class T> struct Foo_helper {};
// specialize Foo_helper for each type T you wish to support:
template <> struct Foo_helper<int>
{
template <std::size_t N>
static int get(const Foo& foo) { return foo.i + N; }
};
template <> struct Foo_helper<double>
{
template <std::size_t N>
static double get(const Foo& foo) { return foo.i + N; }
};
int main()
{
Foo foo{};
int i = foo.get<int, 4>();
double d = foo.get<double, 2>();
}
So I was answering this question: Define friend function template of class template, and I found some "weird" behavior from g++ (5.3) and clang (3.8):
Let's assume the following template:
template<int M>
struct test {
private:
int value;
template<int U, int K>
friend test<K> foo (test<U> const t);
};
template <int M, int N = 2 * M>
test<N> foo (test<M> const t) {
test<N> r;
r.value = t.value;
return r;
}
int main(){
test<1> t;
foo(t);
}
This compile with both compiler (as expected - If this should not compile, feel free to comment and explain why).
If I change things to:
template<int U, int K>
friend auto foo(test<U> const t);
template <int M, int N = 2 * M>
auto foo (test<M> const t) { /* ... */ }
This compile with g++ but not with clang, and if I set one to auto and the other one to a specific value, e.g.:
template<int U, int K>
friend test<K> foo(test<U> const t);
template <int M, int N = 2 * M>
auto foo (test<M> const t) { /* ... */ }
// or:
template<int U, int K>
friend auto foo(test<U> const t);
template <int M, int N = 2 * M>
test<N> foo (test<M> const t) { /* ... */ }
Both compiler reject the code saying that:
error: 'int test<2>::value' is private
My two related questions are:
Which compiler is right for the first case (auto for both declaration/definition)?
Why is not possible to use auto when defining the function and test<K> when declaring the friendship?
Or in one question: What are the rules about auto for friend function declarations when the function is defined outside the class?
Consider [dcl.spec.auto]/13:
Redeclarations or specializations of a function or function template
with a declared return type that uses a placeholder type shall also
use that placeholder, not a deduced type.
I.e. if the friend declaration uses auto and the second declaration does not, they don't match. The other way around is guaranteed by core issue 2081. Finally, if both use auto, the declarations should indeed match as per [temp.over.link]/6, so Clang is incorrect in that case.