I am implementing a library in C/C++11 and I have chosen to follow Google C++ Style Guide as I also use this style guide in my code.
As such all classes and types (including typedefs
and using
) start with a capital letter.
However I have reached a conflict when implementing some traits.
For instance I have a RemoveOptional
trait:
template <class T>
struct RemoveOptional {
using Type = T;
};
template <class T>
struct RemoveOptional<utils::Optional<T>> {
using Type = T;
};
that I can use like this:
utils::RemoveOptional<utils::Optinal<int>>::Type
But for the traits like IsXXX I have chosen to inherit std::true_type
or std::false_type
in order to be used like the std
traits:
template <class T>
struct IsOptional : std::false_type {
};
template <class T>
struct IsOptional<Optional<T>> : std::true_type {
};
so this trait is used like this:
utils::IsOptional<utils::Optional<int>>::value
utils::IsOptional<utils::Optional<int>>::value_type
And value_type
conflicts with my naming conventions as it should be ValueType
.
As far as I see I have 3 options:
Modify all of my traits to follow the
std
convention.- Advantages: my traits can be checked against the
std::true_type
andstd::false_type
. - Disadvantages: my library is inconsistent.
- Advantages: my traits can be checked against the
Discard the
std::true_type
andstd::false_type
and make all my traits following my convention.- Advantages: my library is consistent.
- Disadvantages: my traits can't be checked against
std::true_type
andstd::false_type
.
Leave as it is now.
- Advantages: my traits can be checked against
std::true_type
andstd::false_type
. - Disadvantages: my library is inconsistent (even my traits are inconsistent between each other).
- Advantages: my traits can be checked against
What should I do?
-
\$\begingroup\$ I am not certain this question belongs on CodeReview. Perhaps Programmers is a better site? \$\endgroup\$rolfl– rolfl2014年01月04日 16:50:54 +00:00Commented Jan 4, 2014 at 16:50
-
\$\begingroup\$ When that guide isn't discussing small stuff like naming conventions and indentation, it promotes some of the worst coding practices imaginable. Don't use it for your code if you want to be taken seriously (or at least make a disclaimer like "naming convention follows GSG C++"). \$\endgroup\$Cubbi– Cubbi2014年01月05日 15:58:21 +00:00Commented Jan 5, 2014 at 15:58
-
\$\begingroup\$ Don't use the "Googel Style Guide". It is good for internal google usage only. Its guidance is outdated and bad in many places for use with real C++. \$\endgroup\$Loki Astari– Loki Astari2014年01月06日 21:34:01 +00:00Commented Jan 6, 2014 at 21:34
-
\$\begingroup\$ Though I do agree with using a capitol letter as the first letter of a type name. It helps distinguish types from other identifiers. But follow the standard conventions when mirroring standard types. \$\endgroup\$Loki Astari– Loki Astari2014年01月06日 21:35:10 +00:00Commented Jan 6, 2014 at 21:35
-
\$\begingroup\$ @LokiAstari What guides do you recommend for C++? I know it's a subjective question, and that's why I don't post a formal question on SO, but I am really interested in a good (and fairly used) C++ style guide. \$\endgroup\$bolov– bolov2014年01月06日 23:22:11 +00:00Commented Jan 6, 2014 at 23:22
1 Answer 1
There is no single correct answer in all circumstances. You have to weigh the costs and benefits of the alternatives. Oddly enough my analysis seems to match yours, but here's one additional alternative you didn't explicitly cover:
Add redundant typedefs. All types you create will follow your standard, and those from the standard library will not. However you can easily provide aliases that expose parts of the standard library using names of your choosing. This is a little more code than the first option, and provides an opportunity for users of your class to use either name they like. If more than one name is used, the readability of the code can suffer. As such, while this initially may look like it combines the best of both extremes, in reality it also offers the worst.
template <class T> struct IsOptional : std::false_type { using Type = std::false_type::value_type; using Value = std::false_type::value; }; template <class T> struct IsOptional<Optional<T>> : std::true_type { using Type = std::true_type::value_type; using Value = std::true_type::value; };
However, once you're done writing the library, I would posit this is not all that important. I do not routinely use std::true_type
or std::false_type
when consuming a library. Template specialization is typically used to achieve two objectives at the same time:
- Make the classes easy to use in flexible ways
- Make the code that uses the classes really fast
Neither of these objectives really involve the consumers of the library having to care about the names of the types used in specializing its templates.
And thus my answer is this: don't sweat it. Do what makes you, and anyone else who is helping to implement your library, happy. This probably means choose the least amount of work, leaving you with mismatched conventions, but the ability to leverage knowledge of working with the standard library, but could mean writing your own TrueType
and FalseType
classes that follow your chosen naming conventions.
-
\$\begingroup\$ Thank you. I work alone on it so I am the only one who needs to be happy :). I know I tend to overthink this kind of things so I will leave it now as it is. I think I will write my own
TrueType
andFalseType
later on. \$\endgroup\$bolov– bolov2014年01月04日 15:32:38 +00:00Commented Jan 4, 2014 at 15:32