CSS Grid: Universal row column CSS rules which abstract away specific column and row counts - css-grid

I want to leverage CSS Grid to evenly size those elements which are part of the same CSS Grid axis:
[class*=' container-grid-'], [class^='container-grid-'] {
/* give margin-bottom to all kinds of "container-grid-", see https://stackoverflow.com/a/13352103/923560 */
margin-bottom: 2rem;
}
[class*=' container-grid-'] > .col, [class^='container-grid-'] > .col {
display: contents;
}
.container-grid-2by2 {
display: grid;
grid-auto-flow: column;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, auto);
row-gap: 0;
column-gap: 1rem;
}
.container-grid-3by3 {
display: grid;
grid-auto-flow: column;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, auto);
row-gap: 0;
column-gap: 1rem;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.blue {
background-color: skyblue;
}
.limit-width {
max-width: 20rem;
background-color: silver;
}
<div class="limit-width">
<h1><code>.container-grid-2by2</code></h1>
<div class="container-grid-2by2">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid-3by3</code></h1>
<div class="container-grid-3by3">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz3
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3 Bar3 Bar3 Bar3 Bar3
</div>
<div class="blue">
Baz3
</div>
</div>
</div>
</div>
As you can see, elements on the same CSS grid row axis receive the same height, e.g. a cell with little text content (Foo1) stretches to match the height of the cell with most text content (Foo2 Foo2 Foo2 ...). Awesome, that's exactly what I want!
HTML follows the following structure: a <div class="container-grid-*"> element acting as the CSS grid container; inside it several <div class="col"> acting as columns; and then inside those columns the actual content HTML elements. The .col elements use display: contents; to "delegate" CSS grid cell determination to the actual content HTML elements.
But right now, my CSS requires explicit rules for each column and row count: .container-grid-2by2, .container-grid-3by3, .container-grid-2by3, .container-grid-3by2, etc.
There should be a way to refactor this, no?
Is there any CSS trick to automatically derive CSS grid column and row counts?
For my circumstances, it can always be assumed that within a container, each column has the same amount of actual HTML content elements; e.g. within a container all columns will have x elements.

I found two solutions which haven't gone the full way of generalization, and rely on workaround and hacks.
Not-so-hacky solution
Successfully tested in Chrome 96 and Firefox 94.
This solution relies on a "pre-calculated" set of CSS rules, putting the nth-child(x) .col child into the x's grid-row. As the .container-grid is defines a completely implicit (versus explicit) CSS grid, the next .col's first element will automatically introduce the next column and be placed in that next column.
.container-grid {
display: grid;
row-gap: 0;
column-gap: 1rem;
grid-auto-columns: 1fr;
}
.container-grid > .col {
display: contents;
}
.container-grid > .col > div:nth-child(1) {
grid-row: 1;
}
.container-grid > .col > div:nth-child(2) {
grid-row: 2;
}
.container-grid > .col > div:nth-child(3) {
grid-row: 3;
}
.container-grid > .col > div:nth-child(4) {
grid-row: 4;
}
/* ... and so on up to the maximum amount of vertical grid elements you can imagine in each row */
.red {
background-color: red;
}
.green {
background-color: green;
}
.blue {
background-color: skyblue;
}
.yellow {
background-color: yellow;
}
.limit-width {
max-width: 30rem;
background-color: silver;
}
<div class="limit-width">
<h1><code>.container-grid</code> 1col x 1row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 1col x 2row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 2col x 1row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 2col x 2row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 2col x 3row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz2
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 3col x 2row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 3col x 3row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz2
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3
</div>
<div class="blue">
Baz3
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 4col x 3row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz2
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3
</div>
<div class="blue">
Baz3
</div>
</div>
<div class="col">
<div class="red">
Foo4
</div>
<div class="green">
Bar4
</div>
<div class="blue">
Baz4
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 4col x 4row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
<div class="yellow">
Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz2
</div>
<div class="yellow">
Qux2
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3
</div>
<div class="blue">
Baz3
</div>
<div class="yellow">
Qux3 Qux3 Qux3 Qux3
</div>
</div>
<div class="col">
<div class="red">
Foo4
</div>
<div class="green">
Bar4
</div>
<div class="blue">
Baz4
</div>
<div class="yellow">
Qux4
</div>
</div>
</div>
</div>
Awfully hacky solution
Successfully tested in Chrome 96 and Firefox 94.
This solution relies on a ::after pseudo-element for each .col: this pseudo-element occupies/hacks in enough extra grid-row to overflow into a next implicit column. The 0 in grid-auto-columns: 1fr 0; makes sure that this phantom column occupies no horizontal space.
This solution relies on the hack to give an explicitly high value for the pseudo-element grid-row value.
.container-grid {
display: grid;
row-gap: 0;
column-gap: 0.5rem; /* column-gap is created for both .col and pseudo-element phantom column, therefore to achieve an effective column-gap of 1rem, we use the half value of 0.5rem */
grid-auto-flow: column;
grid-auto-columns: 1fr 0; /* 1fr is for each .col, 0 is for its follow-up pseudo-element phantom column to occupy no horizontal space */
}
.container-grid > .col {
display: contents;
}
.container-grid > .col::after {
content: "";
grid-row: span 8; /* span x, where x is the maximum amount of elements that will every be in a column */
background-color: pink;
}
.container-grid > .col:only-child::after {
/* ugly fix for the case of 1col x 1row and 1col x 2row */
grid-row: 9; /* y, where y = x + 1, where x is the maximum amount of elements that will every be in a column */
}
.container-grid > .col:not(:first-child):last-child::after {
/* last .col shall not create a follow-up pseudo-element phantom column
content: unset;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.blue {
background-color: skyblue;
}
.yellow {
background-color: yellow;
}
.limit-width {
max-width: 30rem;
background-color: silver;
}
<div class="limit-width">
<h1><code>.container-grid</code> 1col x 1row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 1col x 2row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 2col x 1row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 2col x 2row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 2col x 3row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz2
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 3col x 2row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 3col x 3row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz2
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3
</div>
<div class="blue">
Baz3
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 4col x 3row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz2
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3
</div>
<div class="blue">
Baz3
</div>
</div>
<div class="col">
<div class="red">
Foo4
</div>
<div class="green">
Bar4
</div>
<div class="blue">
Baz4
</div>
</div>
</div>
</div>
<div class="limit-width">
<h1><code>.container-grid</code> 4col x 4row</h1>
<div class="container-grid">
<div class="col">
<div class="red">
Foo1
</div>
<div class="green">
Bar1
</div>
<div class="blue">
Baz1
</div>
<div class="yellow">
Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1
</div>
</div>
<div class="col">
<div class="red">
Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
</div>
<div class="green">
Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
</div>
<div class="blue">
Baz2
</div>
<div class="yellow">
Qux2
</div>
</div>
<div class="col">
<div class="red">
Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3
</div>
<div class="green">
Bar3 Bar3 Bar3 Bar3
</div>
<div class="blue">
Baz3
</div>
<div class="yellow">
Qux3 Qux3 Qux3 Qux3
</div>
</div>
<div class="col">
<div class="red">
Foo4
</div>
<div class="green">
Bar4
</div>
<div class="blue">
Baz4
</div>
<div class="yellow">
Qux4
</div>
</div>
</div>
</div>
UPDATE: It seems that the awfully hacky solution doesn't work via
Run code snippet, but it works in the Code Snippet Editor.

Related

C++ tamplate class instances which reference to each other [duplicate]

I'm looking to create two classes, each of which contains an object of the other class type. How can I do this? If I can't do this, is there a work-around, like having each class contain a pointer to the other class type? Thanks!
Here's what I have:
File: bar.h
#ifndef BAR_H
#define BAR_H
#include "foo.h"
class bar {
public:
foo getFoo();
protected:
foo f;
};
#endif
File: foo.h
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo {
public:
bar getBar();
protected:
bar b;
};
#endif
File: main.cpp
#include "foo.h"
#include "bar.h"
int
main (int argc, char **argv)
{
foo myFoo;
bar myBar;
}
$ g++ main.cpp
In file included from foo.h:3,
from main.cpp:1:
bar.h:6: error: ‘foo’ does not name a type
bar.h:8: error: ‘foo’ does not name a type
You cannot have two classes directly contain objects of the other type, since otherwise you'd need infinite space for the object (since foo has a bar that has a foo that has a bar that etc.)
You can indeed do this by having the two classes store pointers to one another, though. To do this, you'll need to use forward declarations so that the two classes know of each other's existence:
#ifndef BAR_H
#define BAR_H
class foo; // Say foo exists without defining it.
class bar {
public:
foo* getFoo();
protected:
foo* f;
};
#endif
and
#ifndef FOO_H
#define FOO_H
class bar; // Say bar exists without defining it.
class foo {
public:
bar* getBar();
protected:
bar* f;
};
#endif
Notice that the two headers don't include each other. Instead, they just know of the existence of the other class via the forward declarations. Then, in the .cpp files for these two classes, you can #include the other header to get the full information about the class. These forward declarations allow you to break the reference cycle of "foo needs bar needs foo needs bar."
That doesn't make sense. If A contains B, and B contains A, it would be infinite size. Imagine putting having two boxes and trying to put both into each other. Doesn't work, right?
Pointers work though:
#ifndef FOO_H
#define FOO_H
// Forward declaration so the compiler knows what bar is
class bar;
class foo {
public:
bar *getBar();
protected:
bar *b;
};
#endif

C++ "Importing" an enum class from another C++ file

I'm a coming from a Java background so please bear with me on this :)
I'm trying to "import" (to use Java terminology) an enum class from another C++ file so as to be able to use it directly without having to prefix it with the class name.
So for instance, let's say I have this in a header file:
class Foo
{
public:
enum class Bar {ITEM_1, ITEM_2};
void doThings(Bar bar);
};
Now, currently, if I want to use Bar from another C++ file, I do this:
#include "Foo.h"
void Foo2::methodInAnotherFile()
{
Foo foo();
Foo::Bar bar = Foo::Bar::ITEM_2;
foo.doThings(bar);
}
Now what I'd like to do is to be able to do something like "import" (to use Java terminology) Bar so as to be able to remove the need to prefix Bar with Foo::, i.e. do Bar bar = Bar::ITEM_2;.
Now, with my limited knowledge of C++, one way I can think of doing this would be to surround all the code in Foo.h with namespace FooNamespace{}, take the Bar enum out of the class (but still in the namespace), and then add using namespace FooNamespace to the top of the Foo2 class. However, for my application that really doesn't make much logical sense, as the Bar enum really logically belongs inside that Foo class.
Since I'm proficient in Java, here's a Java example of what I'd like to do:
File 1:
package org.fooclass;
public class Foo
{
public static enum Bar
{
ITEM_1,
ITEM_2;
}
public void doThings(Bar bar)
{
System.out.println("Item: " + bar.toString());
}
}
File 2:
package org.foo2class;
import org.fooclass.Foo;
import org.fooclass.Foo.Bar; //I want to do THIS in C++
public class Foo2
{
public void methodInAnotherFile()
{
Foo foo = new Foo();
/*
* Since I've 'imported' Foo.Bar, I can now
* use Bar directly instead of having to do this:
* Foo.Bar bar = Foo.Bar.ITEM2;
*/
Bar bar = Bar.ITEM_2;
foo.doThings(bar);
}
}
Use a type alias via a using statement, eg:
#include "Foo.h"
using Bar = Foo::Bar; // <-- here
void Foo2::methodInAnotherFile()
{
Foo foo;
Bar bar = Bar::ITEM_2;
foo.doThings(bar);
}
Or, to limit its scope:
#include "Foo.h"
void Foo2::methodInAnotherFile()
{
using Bar = Foo::Bar; // <-- here
Foo foo;
Bar bar = Bar::ITEM_2;
foo.doThings(bar);
}

Remove duplicate code with similar factory classes

I have this code:
struct Foo1 {}
struct Foo1Helper {} // generated
struct Foo2 {}
struct Foo2Helper {} // generated
struct Foo1Factory {
Foo1* Create(){
return connect();
}
protected:
Foo1 *connect();
}
// cpp file (important because i don't want to have Foo1Helper in .h file)
Foo1* Foo1Factory::connect(){
return Foo1Helper::doSmth();
}
struct Foo2Factory {
Foo2* Create(){
return connect();
}
protected:
Foo2 *connect();
}
// cpp file (important because i don't want to have Foo2Helper in .h file)
Foo2* Foo2Factory::connect(){
return Foo2Helper::doSmth();
}
I have two classes Foo1 and Foo2, and both are created with a factory class with the help of the Foo1Helper and Foo2Helper classes.
The idea is to somehow have just one Factory class because there is a lot of duplicate code, the only difference is the helper function which is called in the connect function.
Note: I want to hide the Helper classes from the header files so the connect function must be implemented in .cpp file.
You can have one Factory if you can live with defining some aliases and you can hide your Helper classes in cpp if you can live with some explicit template instantiations. And I don't see why you wouldn't.
In the following I made the assumption your factory methods are static. If they are not, it can be easily adapted with the pimpl idiom.
header file
struct Foo1 { /* implementation */ };
struct Foo1Helper; // just declaration
struct Foo2 { /* implementation */ };
struct Foo2Helper; // just declaration
// a little helper
template <class Foo_main, class Helper>
struct Foo_trait
{
using Foo = Foo_main;
using FooHelper = Helper;
};
// this section can be easily generated
// if you have a lot of classes and feel particularly lazy
using Foo1_trait = Foo_trait<Foo1, Foo1Helper>;
using Foo2_trait = Foo_trait<Foo2, Foo2Helper>;
// just one Factory class
// no implementation exposed to the header
template <class Foo_trait>
struct FooFactory
{
using Foo = typename Foo_trait::Foo;
using FooHelper = typename Foo_trait::FooHelper;
static auto Create() -> Foo*;
};
source file
struct Foo1Helper
{
static Foo1* doSmth()
{
static Foo1 f;
return &f;
}
};
struct Foo2Helper
{
static Foo2* doSmth()
{
static Foo2 f;
return &f;
}
};
template <class Foo_trait>
auto FooFactory<Foo_trait>::Create() -> Foo*
{
return FooHelper::doSmth();
}
// explicit template instantiation
// very important. Without this you get linker erorrs
// again very easy to generate
template struct FooFactory<Foo1_trait>;
template struct FooFactory<Foo2_trait>;
usage
Foo1 f1 = FooFactory<Foo1_trait>::Create();
Foo2 f2 = FooFactory<Foo2_trait>::Create();
If you have control over FooN then you can skip the Foo_trait altogether and define an alias inside FooN. E.g.
struct Foo1
{
using Helper = Foo1Helper;
};

Two objects in namespace to be default initialized by different functions and used by class within namespace

I have a strange request. I have a namespace foo with two declared objects of type bar, namely bar1 and bar2, which I would like to initialize via constructor of class bar. Is this a sound way to do so:
namespace foo {
class bar;
foo::bar *bar1;
foo::bar *bar2;
}
class foo::bar
{
/* Initialize bar1 and bar2 in the constructor.
*/
InitializeBar();
};
The reason behind this shenanigan is I would like to create an object similar to cout and cin such that foo::bar1 and foo::bar2 need not be defined by the user. More specifically, I am using ncurses and wish to replace cout with an output window bar1 and cin with an input window bar2 and overload the operators and such that foo::bar1 << a prints a in the output window as I see fit and foo::bar2 >> b extracts the values from the input window and dumps it into b. I am able to do this via the C functions call but I need help to extend it to C++. Perhaps default initialization of bar1 and bar2 accordingly?
One way is to use the simple function pattern. You keep the constructor as private and the clients can only access these objects via two get functions. You probably want to disable the copy constructor and copy assignment operator as well.
// .h
namespace foo
{
class bar: boost noncopyable
{
public:
static bar* getInputWindow()
{
static bar s_input;
return &s_input;
}
static bar* getOutputWindow()
{
static bar s_output;
return &s_output;
}
private:
bar()
{
}
};
// global/namespace objects clients should directly use
extern bar *input;
extern bar *output;
}
// .cpp
namespace foo
{
bar *input = bar::getInputWindow();
bar *output = bar::getOutputWindow();
}

Way To Access A Variable In All Methods Of Class Except Defining As Global Variables

Is there any way to access a variable in all of my methods in a class(except using global varibles that defines above of cpp file)??
TIA
foo.h
class Foo {
static int bar;
void foo ();
};
void foo ();
foo.cpp
int Foo :: bar = 123;
void Foo :: foo () {
++bar; // ok
}
void foo () {
++ bar; // Error! Not in scope.
++ Foo :: bar; // Error! Private.
}
You mean a static data member of the class?
The other answers are correct, but I didn't read your question as meaning it is the same across Foo objects which is what making it as static here will do (as well as making it interesting across multi-threaded code). You can also make it just a private variable such as here:
Header:
class Foo
{
private:
int bar;
void foo ();
public:
Foo();
};
Class:
Foo::Foo() : bar(123) {}
void Foo :: foo ()
{
// Will update its own bar, but not every other Foo object that exists
++bar; // ok
}
But maybe the static way is what you wanted :-)