Bug of gcc? Access control issue about friend function in template class - c++

I have a template class, and I define a friend function inside the class.
#include <iostream>
using namespace std;
template <typename T>
class template_class {
T v;
friend void foo(template_class t) {
t.v = 1; // (1)can access the private member because it's a friend
cout << t.v << endl;
template_class<int> t1;
t1.v = 2; // (2)accessible if instantiated with [T=int]
cout << t1.v << endl;
template_class<char> t2;
t2.v = 'c'; // (3)should not be accessible too if instantiated with [T=int]
cout << t2.v << endl;
}
};
int main() {
template_class<int> t; // (4)generate void foo(template_class<int> t)
foo(t);
return 0;
}
If my understanding is correct, (4) generate the function void foo(template_class<int>), and make it the friend of template_class<int>, so it can access the private member of template_class<int> like (1) and (2) in above source. But (3) should not be OK too, it's not the friend of template_class<char>, only void foo(template_class<char>) will be the friend of template_class<char>.
EDIT
As #Constructor and #Chnossos said, The above source compiled OK with gcc 4.8.1, but failed with clang 3.4. So which one is correct? Is it just a bug of gcc? Does the standard has an explicit definition about this case?

As dyp says in the comments, this is simply a GCC bug. Either PR 41437 or one of the others that PR 59002 links to.

Related

How to name class identifier in assignment in c++?

From here: Difference between 'struct' and 'typedef struct' in C++?, I found I need class identifier if there is name collision (for example if class name is the same as function name):
#include <iostream>
using namespace std;
class foo
{
public:
foo() {}
operator char const *() const
{
return "class";
}
};
char const *foo()
{
return "function\n";
}
int main()
{
char const *p;
p = class foo(); //this gets error
cout << p << '\n';
return 0;
}
output:
error: expected primary-expression before ‘class’
p = class foo();
What is primary expression here and how can I identify the class instead of the function? I would like it to print class instead of function. How to do so?
One of the possible solutions:
using bar = class foo;
p = bar();
int main()
{
char const *p;
struct foo f;
p = static_cast<char const*>(f);
cout << p << '\n';
return 0;
}
By the way, the answer you link mentions that one can use typedef class foo foo; to trigger a compiler error for a function of same name. Havning a class and a function of same name isn't something desirable, but rather you need to workaround a bit the fact that the language allows it. And don't miss the last paragraph:
I can't imagine why anyone would ever want to hide a class name with a
function or object name in the same scope as the class. The hiding
rules in C were a mistake, and they should not have been extended to
classes in C++. Indeed, you can correct the mistake, but it requires
extra programming discipline and effort that should not be necessary.
If you are in control of either the function or the class you should definitely rename it or place it inside a namespace.
I found two solutions that are accepted by both g++ and clang. I do not know, however, if they are standard C++.
Uniform initialization
cout << (class foo){} << "\n";
Using a helper
template <typename T, typename ...Args>
T ctor(Args&& ...args) {
return T{ std::forward<Args>(args) ... };
}
// ...
cout << ctor<class foo>() << "\n";

how to return a reference to a default value of a non-type template argument

I have done a lot of research on this but I wasn't able to find a design pattern addressing the problem. This is a minimal description of what I'm trying to perform.
#include <iostream>
using namespace std;
template <class T, T default_value=T{}>
class A{
private:
T inclassValue;
public:
A(T icv):inclassValue{icv}{}
const T& operator[](int k){
if(k==1) return inclassValue;
return default_value;
}
};
struct two_int{int x;int y;};
int main(){
A<int> a{4};
cout << "a[0]=" << a[0] << endl;
cout << "a[1]=" << a[1] << endl;
/*
A<two_int> b{{3,5}};
cout << "b[0]=" << b[0].x << "," << b[0].y << endl;
cout << "b[1]=" << b[1].x << "," << b[1].y << endl;
*/
return 0;
}
The code will compile, link and output as expected
a[0]=0
a[1]=4
The compiler complains though and issues a warning for the line of code where default_value is used
return default_value;//Returning reference to local temporary object
which makes some sense. Uncommenting the last part in main and compiling, the compiler issue this time an error while building the template
template <class T, const T default_value= T{}>//A non-type template parameter cannot have type 'two_int'
while what I ideally hope for is
b[0]=0,0
b[1]=3,5
I was able to come up with a solution by adding an extra helper class, that will provide the default_value of T (as a static member), to the template arguments. I'm not convinced by the robustness of my trick and I was wondering if there exists a design pattern addressing this. The warning for types and the error for non-types. Also, I shall add that my primary goal is to be able to provide default_value at will (6 for int for example instead of 0).
Thanks
Not exactly sure what you're looking for, but perhaps a static helper finishing for creating a static default T could be useful:
template <typename T>
static const T& default_value() {
static const T* t = new T{};
return *t;
}
Note this will construct T at most once even across threads (in c++11), but still never destruct T. Since it's static, it's likely the lack of destruction is acceptable, but this of course depends on T.
Here is one version that forwards arguments to the constructor of a default_value stored as constexpr. You are quite limited here as to what is valid to pass as arguments (not sure exactly how limited) so it will depend on your use-case.
#include <iostream>
using namespace std;
template <class T, auto... Args>
class A{
private:
T inclassValue;
constexpr static T default_val = T{Args...}; // Changed to curly brackets here
public:
constexpr A(T icv):inclassValue{icv}{}
const T& operator[](int k){
if(k==1) return inclassValue;
return default_val;
}
};
struct two_int{int x;int y;};
int main(){
A<int> a{4};
cout << "a[0]=" << a[0] << endl;
cout << "a[1]=" << a[1] << endl;
A<two_int> b{{3,5}};
cout << "b[0]=" << b[0].x << "," << b[0].y << endl;
cout << "b[1]=" << b[1].x << "," << b[1].y << endl;
return 0;
}

GCC shared_ptr and make_shared on map separated var type error

I want to use std::shared_ptr and std::make_shared and create a map list with separated variable types ... My compiler is GCC and this is my source
#include <iostream>
#include <cstring>
#include <memory>
#include <string>
#include <map>
using namespace std;
class key_base {
public:
virtual ~key_base() = default;
key_base() = default;
template <typename T> const T & Read();
};
template <typename T>
class key : public key_base {
private:
T storage_;
public:
key(const T & __storage) {
storage_ = __storage;
}
const T & Read() { return storage_; }
};
int main() {
map <int, std::shared_ptr <key_base>> List;
List[0] = std::make_shared <key<string>>("Hello");
List[1] = std::make_shared <key<string>>("How old are you?");
List[2] = std::make_shared <key<int>>(22);
for (auto thisItem : List) {
if(thisItem.first == 2)
cout << thisItem.first << "= (" << thisItem.second->Read<int>() << ")" << endl;
else
cout << thisItem.first << "= (" << thisItem.second->Read<string>() << ")" << endl;
}
return 0;
}
I know one thing about key_base (Read) function which need to be virtual and = 0 and also it's must be template (to get the type of var) and it's not possible in GCC (but possible in Microsoft Compiler). What should I do for this too?
Problem is that you think that dynamic polymorphism will work with templates.
Basically template declaration template <typename T> const T & Read(); in base_class is completely useless.
How do you think compiler deduce what should be done for Read() if base class is used? There is no definition of this template and compiler has no idea how to reach subclasses where you are defining this methods.
Your design is wrong and since this is classic XY problem we are unable to help you to resolve this properly.
Looks like you should take a look on new template from C++17:
std::any
To make it work (I hate the code design), you need add missing template definition after key class:
template <typename T>
const T & key_base::Read()
{
if (auto subClassObject = dynamic_cast<key<T> *>(this)) {
return subClassObject->Read();
}
throw domain_error { "Invalid Read use" };
}
It works for Visual Studio.
And it works for GCC.

Trailing return types and tag dispatching

Experimenting with trailing return types and tag dispatching, I have written the following code.
#include <string>
#include <iostream>
using namespace std;
namespace Params
{
struct t_param1{};
struct t_param2{};
};
template<typename t_detail>
struct Select;
template<>
struct Select<Params::t_param1> {using choice = Params::t_param1;};
template<>
struct Select<Params::t_param2> {using choice = Params::t_param2;};
class Tester
{
private:
using t_uint32 = uint32_t;
using t_string = string;
private:
t_uint32 m_param1;
// t_string m_param2;
private:
template<typename t_entity>
void assign(const Params::t_param1&, t_entity&& entity);
template<typename t_entity>
void assign(const Params::t_param2&, t_entity&& entity);
auto access(const Params::t_param1&) -> decltype(m_param1);
// auto access(const Params::t_param2&) -> decltype(m_param2);
public:
template<typename t_detail, typename t_entity>
void assign(t_entity&& entity);
template<typename t_detail>
auto access() -> decltype(access(typename Select<t_detail>::choice()));
};
template<typename t_detail, typename t_entity>
void
Tester::assign(t_entity&& entity)
{
assign(typename Select<t_detail>::choice(), entity);
}
template<typename t_entity>
void
Tester::assign(const Params::t_param1&, t_entity&& entity)
{
m_param1 = entity;
cout << "Assigned m_param1 with " << entity << endl;
}
/*
template<typename t_entity>
void
Tester::assign(const Params::t_param2&, t_entity&& entity)
{
m_param2 = entity;
cout << "Assigned m_param2 with " << entity << endl;
}
*/
template<typename t_detail>
auto
Tester::access()
-> decltype(access(typename Select<t_detail>::choice()))
{
return(access(typename Select<t_detail>::choice()));
}
auto
Tester::access(const Params::t_param1&)
-> decltype(m_param1)
{
return(m_param1);
}
/*
auto
Tester::access(const Params::t_param2&)
-> decltype(m_param2)
{
return(m_param2);
}
*/
int main() {
auto tester = Tester();
tester.assign<Params::t_param1>(79);
// tester.assign<Params::t_param2>("viziv");
auto param1 = tester.access<Params::t_param1>();
// auto param2 = tester.access<Params::t_param2>();
cout << "Access: param1 = " << param1 << endl;
// cout << "Access: param2 = " << param2 << endl;
return 0;
}
when I compile this code using Apple LLVM version 7.0.2 (clang-700.1.81), I get the following compilation error
junk1.cpp:78:9: error: out-of-line definition of 'access' does not match any declaration in 'Tester'
Tester::access()
^~~~~~
1 error generated.
Curiously, when I uncomment the code to assign and access param2 (commented out in the above code), it compiles fine and produces the required result.
What am I doing wrong? Could anyone please explain to me why the inclusion of param2 change in compilation behaviour?
I think there is one and a half issues going on here.
The first lies in that using a trailing return type essentially creates a templated function. When you attempt to use a class' function, the class type must not be incomplete.
That is why moving the function definition for the public access method into the class declaration fixes it (Demo); the class is otherwise incomplete so long as the public access method hasn't been defined, and that method cannot be defined until the class is complete.
Note that another way to fix this would be if the private version of access were somehow a non-member function (e.g., a free-floating function in the surrounding scope).
The problem with that approach (half of a problem, because you're not actually trying to do this) is that, trying to call the now-free floating version of access requires the compiler to evaluate all possible overloads, including the public templated access (Thanks to ADL). When that happens, Select<t_detail>::choice is evaluated in a non-deduced context, and the actual underlying type cannot be obtained.
So, if we both moved the private access outside of Tester and renamed it (to something like access2), then we are allowed to separate the declaration and the definition of the public access function (Demo)

Template Run version Different from Debug

I have an object like the following
template<typename T>
inline void UnusedParameter( T const& )
{
}
class Client
{
public:
template<class T>
void runFFT(T *wSamples, float const &fMult)
{
std::cout << "INSIDE RUNFFT : : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
};
And in my CPP I have the following:
#include "object.hpp"
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult)
{
std::cout << "INSIDE INT16_T version: : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult)
{
std::cout << "INSIDE IPP32F version: : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
Both these implementation run without any problem in my Debug Code. It enters the int16_t version without problem and the Ipp32f version also without problem.
But when I try the Run version it only enters the Template, like the compiler only compiles the Template implementation in the header.
How do I prevent this from happenning? Shall I remove this and just create two different methods? I love my templates but these Heisenberg bugs are frustating.
Thanks for any input.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Andy Prowl answered this question and it is solved doing the following in the HPP:
template<typename T>
inline void UnusedParameter( T const& )
{
}
class Client
{
public:
template<class T>
void runFFT(T *, float const &)
{
// Thanks for Joachim for removing my Unused Parameter crap
std::cout << "INSIDE RUNFFT : : :" << std::endl;
}
};
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult);
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult);
And now it works in runtime as well. The CPP stays the same.
The problem is most likely in the fact that you relegated the specializations of your member function runFFT() for int16_t and Ipp32f in a separate .cpp file without providing a corresponding declaration after the primary template, so the compiler at the point of instantiation (which likely belongs to another translation unit that #includes only the header file containing the definition of Client) doesn't know about the existence of those explicit specializations.
Put a declaration for those specializations in the same header file that contains the definition of your class template:
template<typename T>
inline void UnusedParameter( T const& ) { }
class Client
{
public:
template<class T>
void runFFT(T *wSamples, float const &fMult)
{
std::cout << "INSIDE RUNFFT : : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
};
// DECLARE YOUR EXPLICIT SPECIALIZATIONS HERE
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult);
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult);
Per Paragraph 14.7.3/6 of the C++11 Standard:
If a template, a member template or a member of a class template is explicitly specialized then that specialization
shall be declared before the first use of that specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs; no diagnostic is required. [...]
The "no diagnostic is required" part means that if you don't follow this rule, your program will be ill-formed, but your compiler/linker is not required to tell you. This normally results in the kind of undefined behavior you are observing.