Multiple variable template specializations with std::enable_if
I'm trying to concisely define a variable template with these effective values:
// (template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;)
// float and double scalar definitions:
const double huge = std::scalbn(1, EXP<double>);
const float huge = std::scalbn(1, EXP<float>);
// SIMD vector definitions:
const Vec8f huge = Vec8f(huge<float>); // vector of 8 floats
const Vec8d huge = Vec8d(huge<double>); // vector of 8 doubles
const Vec4f huge = Vec4f(huge<float>); // vector of 4 floats
// Integral types should fail to compile
The VecXX vector definitions (SIMD vectors) need to use the corresponding scalar type as shown (e.g. huge<float>
for vector of float
s). This is available as VecXX::value_type
or through a type traits-style template class (VectorTraits<VecXX>::value_type
).
Ideally I think I'd have something like:
// Primary. What should go here? I want all other types to not compile
template<typename T, typename Enabler = void>
const T huge = T{ 0 };
// Scalar specialization for floating point types:
template<typename T>
const T huge<T> = std::enable_if_t<std::is_floating_point<T>::value, T>(std::scalbn(1, EXP<T>));
// Vector specialization, uses above declaration for corresponding FP type
template<typename T>
const T huge<T> = std::enable_if_t<VectorTraits<T>::is_vector, T>(huge<VectorTraits<T>::scalar_type>);
but I can't quite figure out a working version (above fails with "redefinition of const T huge<T>
"). What's the best way to do this?
c++ c++14 sfinae enable-if variable-templates
add a comment |
I'm trying to concisely define a variable template with these effective values:
// (template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;)
// float and double scalar definitions:
const double huge = std::scalbn(1, EXP<double>);
const float huge = std::scalbn(1, EXP<float>);
// SIMD vector definitions:
const Vec8f huge = Vec8f(huge<float>); // vector of 8 floats
const Vec8d huge = Vec8d(huge<double>); // vector of 8 doubles
const Vec4f huge = Vec4f(huge<float>); // vector of 4 floats
// Integral types should fail to compile
The VecXX vector definitions (SIMD vectors) need to use the corresponding scalar type as shown (e.g. huge<float>
for vector of float
s). This is available as VecXX::value_type
or through a type traits-style template class (VectorTraits<VecXX>::value_type
).
Ideally I think I'd have something like:
// Primary. What should go here? I want all other types to not compile
template<typename T, typename Enabler = void>
const T huge = T{ 0 };
// Scalar specialization for floating point types:
template<typename T>
const T huge<T> = std::enable_if_t<std::is_floating_point<T>::value, T>(std::scalbn(1, EXP<T>));
// Vector specialization, uses above declaration for corresponding FP type
template<typename T>
const T huge<T> = std::enable_if_t<VectorTraits<T>::is_vector, T>(huge<VectorTraits<T>::scalar_type>);
but I can't quite figure out a working version (above fails with "redefinition of const T huge<T>
"). What's the best way to do this?
c++ c++14 sfinae enable-if variable-templates
add a comment |
I'm trying to concisely define a variable template with these effective values:
// (template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;)
// float and double scalar definitions:
const double huge = std::scalbn(1, EXP<double>);
const float huge = std::scalbn(1, EXP<float>);
// SIMD vector definitions:
const Vec8f huge = Vec8f(huge<float>); // vector of 8 floats
const Vec8d huge = Vec8d(huge<double>); // vector of 8 doubles
const Vec4f huge = Vec4f(huge<float>); // vector of 4 floats
// Integral types should fail to compile
The VecXX vector definitions (SIMD vectors) need to use the corresponding scalar type as shown (e.g. huge<float>
for vector of float
s). This is available as VecXX::value_type
or through a type traits-style template class (VectorTraits<VecXX>::value_type
).
Ideally I think I'd have something like:
// Primary. What should go here? I want all other types to not compile
template<typename T, typename Enabler = void>
const T huge = T{ 0 };
// Scalar specialization for floating point types:
template<typename T>
const T huge<T> = std::enable_if_t<std::is_floating_point<T>::value, T>(std::scalbn(1, EXP<T>));
// Vector specialization, uses above declaration for corresponding FP type
template<typename T>
const T huge<T> = std::enable_if_t<VectorTraits<T>::is_vector, T>(huge<VectorTraits<T>::scalar_type>);
but I can't quite figure out a working version (above fails with "redefinition of const T huge<T>
"). What's the best way to do this?
c++ c++14 sfinae enable-if variable-templates
I'm trying to concisely define a variable template with these effective values:
// (template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;)
// float and double scalar definitions:
const double huge = std::scalbn(1, EXP<double>);
const float huge = std::scalbn(1, EXP<float>);
// SIMD vector definitions:
const Vec8f huge = Vec8f(huge<float>); // vector of 8 floats
const Vec8d huge = Vec8d(huge<double>); // vector of 8 doubles
const Vec4f huge = Vec4f(huge<float>); // vector of 4 floats
// Integral types should fail to compile
The VecXX vector definitions (SIMD vectors) need to use the corresponding scalar type as shown (e.g. huge<float>
for vector of float
s). This is available as VecXX::value_type
or through a type traits-style template class (VectorTraits<VecXX>::value_type
).
Ideally I think I'd have something like:
// Primary. What should go here? I want all other types to not compile
template<typename T, typename Enabler = void>
const T huge = T{ 0 };
// Scalar specialization for floating point types:
template<typename T>
const T huge<T> = std::enable_if_t<std::is_floating_point<T>::value, T>(std::scalbn(1, EXP<T>));
// Vector specialization, uses above declaration for corresponding FP type
template<typename T>
const T huge<T> = std::enable_if_t<VectorTraits<T>::is_vector, T>(huge<VectorTraits<T>::scalar_type>);
but I can't quite figure out a working version (above fails with "redefinition of const T huge<T>
"). What's the best way to do this?
c++ c++14 sfinae enable-if variable-templates
c++ c++14 sfinae enable-if variable-templates
edited Dec 31 '18 at 9:30
ZachB
asked Dec 30 '18 at 23:42
ZachBZachB
5,31413159
5,31413159
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Not exactly what you asked but I hope the following example can show you how to use SFINAE to specialize a template variable
template <typename T, typename = void>
constexpr T huge = T{0};
template <typename T>
constexpr T huge<T, std::enable_if_t<std::is_floating_point<T>{}>> = T{1};
template <typename T>
constexpr T huge<std::vector<T>> = T{2};
You can check it with
std::cout << huge<int> << std::endl;
std::cout << huge<long> << std::endl;
std::cout << huge<float> << std::endl;
std::cout << huge<double> << std::endl;
std::cout << huge<long double> << std::endl;
std::cout << huge<std::vector<int>> << std::endl;
1
That might be as good as it gets, and I guess I could add another specialization withstd::enable_if</*is vector*/>
to restrict it to vector types.
– ZachB
Dec 31 '18 at 0:25
@ZachB - not sure to understand what do you want but... added specialization
– max66
Dec 31 '18 at 0:31
sorry, I meant that I could add a specialization withstd::enable_if</* is Vec4f or Vec8f or VecXX... */>
. I know how to do that, was just thinking out loud. Thanks!
– ZachB
Dec 31 '18 at 3:41
I've (hopefully) clarified the question and posted the specific solution so far, pointing out the remaining flaws, in case you have any ideas for improvements.
– ZachB
Dec 31 '18 at 9:29
add a comment |
Leaving @max66's answer as the accepted one for the credit, but here's the specific solution I wound up with:
struct _VectorTraits { static constexpr bool is_vector = true; };
template<class T> struct VectorTraits : _VectorTraits { static constexpr bool is_vector = false; };
template<> struct VectorTraits<Vec4f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec8f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec4d> : _VectorTraits { typedef double value_type; };
template<typename T> using EnableIfFP = std::enable_if_t<std::is_floating_point<T>::value>;
template<typename T> using EnableIfVec = std::enable_if_t<VectorTraits<T>::is_vector>;
template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;
// Actual variable template, finally:
template<typename T, typename Enabler = void> const T huge = T{ 0 };
template<typename T> const T huge<T, EnableIfFP<T> > = std::scalbn(1, EXP<T>);
template<typename T> const T huge<T, EnableIfVec<T> > = T{ huge<typename VectorTraits<T>::value_type> };
This could still be improved I think:
- It's verbose.
T
appears 4 times in each specialization's left-hand side. - Integral types (e.g.
huge<uint32_t>
) still compile with a nonsense0
value. I'd rather them not compile.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53982348%2fmultiple-variable-template-specializations-with-stdenable-if%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Not exactly what you asked but I hope the following example can show you how to use SFINAE to specialize a template variable
template <typename T, typename = void>
constexpr T huge = T{0};
template <typename T>
constexpr T huge<T, std::enable_if_t<std::is_floating_point<T>{}>> = T{1};
template <typename T>
constexpr T huge<std::vector<T>> = T{2};
You can check it with
std::cout << huge<int> << std::endl;
std::cout << huge<long> << std::endl;
std::cout << huge<float> << std::endl;
std::cout << huge<double> << std::endl;
std::cout << huge<long double> << std::endl;
std::cout << huge<std::vector<int>> << std::endl;
1
That might be as good as it gets, and I guess I could add another specialization withstd::enable_if</*is vector*/>
to restrict it to vector types.
– ZachB
Dec 31 '18 at 0:25
@ZachB - not sure to understand what do you want but... added specialization
– max66
Dec 31 '18 at 0:31
sorry, I meant that I could add a specialization withstd::enable_if</* is Vec4f or Vec8f or VecXX... */>
. I know how to do that, was just thinking out loud. Thanks!
– ZachB
Dec 31 '18 at 3:41
I've (hopefully) clarified the question and posted the specific solution so far, pointing out the remaining flaws, in case you have any ideas for improvements.
– ZachB
Dec 31 '18 at 9:29
add a comment |
Not exactly what you asked but I hope the following example can show you how to use SFINAE to specialize a template variable
template <typename T, typename = void>
constexpr T huge = T{0};
template <typename T>
constexpr T huge<T, std::enable_if_t<std::is_floating_point<T>{}>> = T{1};
template <typename T>
constexpr T huge<std::vector<T>> = T{2};
You can check it with
std::cout << huge<int> << std::endl;
std::cout << huge<long> << std::endl;
std::cout << huge<float> << std::endl;
std::cout << huge<double> << std::endl;
std::cout << huge<long double> << std::endl;
std::cout << huge<std::vector<int>> << std::endl;
1
That might be as good as it gets, and I guess I could add another specialization withstd::enable_if</*is vector*/>
to restrict it to vector types.
– ZachB
Dec 31 '18 at 0:25
@ZachB - not sure to understand what do you want but... added specialization
– max66
Dec 31 '18 at 0:31
sorry, I meant that I could add a specialization withstd::enable_if</* is Vec4f or Vec8f or VecXX... */>
. I know how to do that, was just thinking out loud. Thanks!
– ZachB
Dec 31 '18 at 3:41
I've (hopefully) clarified the question and posted the specific solution so far, pointing out the remaining flaws, in case you have any ideas for improvements.
– ZachB
Dec 31 '18 at 9:29
add a comment |
Not exactly what you asked but I hope the following example can show you how to use SFINAE to specialize a template variable
template <typename T, typename = void>
constexpr T huge = T{0};
template <typename T>
constexpr T huge<T, std::enable_if_t<std::is_floating_point<T>{}>> = T{1};
template <typename T>
constexpr T huge<std::vector<T>> = T{2};
You can check it with
std::cout << huge<int> << std::endl;
std::cout << huge<long> << std::endl;
std::cout << huge<float> << std::endl;
std::cout << huge<double> << std::endl;
std::cout << huge<long double> << std::endl;
std::cout << huge<std::vector<int>> << std::endl;
Not exactly what you asked but I hope the following example can show you how to use SFINAE to specialize a template variable
template <typename T, typename = void>
constexpr T huge = T{0};
template <typename T>
constexpr T huge<T, std::enable_if_t<std::is_floating_point<T>{}>> = T{1};
template <typename T>
constexpr T huge<std::vector<T>> = T{2};
You can check it with
std::cout << huge<int> << std::endl;
std::cout << huge<long> << std::endl;
std::cout << huge<float> << std::endl;
std::cout << huge<double> << std::endl;
std::cout << huge<long double> << std::endl;
std::cout << huge<std::vector<int>> << std::endl;
edited Dec 31 '18 at 0:30
answered Dec 31 '18 at 0:05
max66max66
36.2k74165
36.2k74165
1
That might be as good as it gets, and I guess I could add another specialization withstd::enable_if</*is vector*/>
to restrict it to vector types.
– ZachB
Dec 31 '18 at 0:25
@ZachB - not sure to understand what do you want but... added specialization
– max66
Dec 31 '18 at 0:31
sorry, I meant that I could add a specialization withstd::enable_if</* is Vec4f or Vec8f or VecXX... */>
. I know how to do that, was just thinking out loud. Thanks!
– ZachB
Dec 31 '18 at 3:41
I've (hopefully) clarified the question and posted the specific solution so far, pointing out the remaining flaws, in case you have any ideas for improvements.
– ZachB
Dec 31 '18 at 9:29
add a comment |
1
That might be as good as it gets, and I guess I could add another specialization withstd::enable_if</*is vector*/>
to restrict it to vector types.
– ZachB
Dec 31 '18 at 0:25
@ZachB - not sure to understand what do you want but... added specialization
– max66
Dec 31 '18 at 0:31
sorry, I meant that I could add a specialization withstd::enable_if</* is Vec4f or Vec8f or VecXX... */>
. I know how to do that, was just thinking out loud. Thanks!
– ZachB
Dec 31 '18 at 3:41
I've (hopefully) clarified the question and posted the specific solution so far, pointing out the remaining flaws, in case you have any ideas for improvements.
– ZachB
Dec 31 '18 at 9:29
1
1
That might be as good as it gets, and I guess I could add another specialization with
std::enable_if</*is vector*/>
to restrict it to vector types.– ZachB
Dec 31 '18 at 0:25
That might be as good as it gets, and I guess I could add another specialization with
std::enable_if</*is vector*/>
to restrict it to vector types.– ZachB
Dec 31 '18 at 0:25
@ZachB - not sure to understand what do you want but... added specialization
– max66
Dec 31 '18 at 0:31
@ZachB - not sure to understand what do you want but... added specialization
– max66
Dec 31 '18 at 0:31
sorry, I meant that I could add a specialization with
std::enable_if</* is Vec4f or Vec8f or VecXX... */>
. I know how to do that, was just thinking out loud. Thanks!– ZachB
Dec 31 '18 at 3:41
sorry, I meant that I could add a specialization with
std::enable_if</* is Vec4f or Vec8f or VecXX... */>
. I know how to do that, was just thinking out loud. Thanks!– ZachB
Dec 31 '18 at 3:41
I've (hopefully) clarified the question and posted the specific solution so far, pointing out the remaining flaws, in case you have any ideas for improvements.
– ZachB
Dec 31 '18 at 9:29
I've (hopefully) clarified the question and posted the specific solution so far, pointing out the remaining flaws, in case you have any ideas for improvements.
– ZachB
Dec 31 '18 at 9:29
add a comment |
Leaving @max66's answer as the accepted one for the credit, but here's the specific solution I wound up with:
struct _VectorTraits { static constexpr bool is_vector = true; };
template<class T> struct VectorTraits : _VectorTraits { static constexpr bool is_vector = false; };
template<> struct VectorTraits<Vec4f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec8f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec4d> : _VectorTraits { typedef double value_type; };
template<typename T> using EnableIfFP = std::enable_if_t<std::is_floating_point<T>::value>;
template<typename T> using EnableIfVec = std::enable_if_t<VectorTraits<T>::is_vector>;
template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;
// Actual variable template, finally:
template<typename T, typename Enabler = void> const T huge = T{ 0 };
template<typename T> const T huge<T, EnableIfFP<T> > = std::scalbn(1, EXP<T>);
template<typename T> const T huge<T, EnableIfVec<T> > = T{ huge<typename VectorTraits<T>::value_type> };
This could still be improved I think:
- It's verbose.
T
appears 4 times in each specialization's left-hand side. - Integral types (e.g.
huge<uint32_t>
) still compile with a nonsense0
value. I'd rather them not compile.
add a comment |
Leaving @max66's answer as the accepted one for the credit, but here's the specific solution I wound up with:
struct _VectorTraits { static constexpr bool is_vector = true; };
template<class T> struct VectorTraits : _VectorTraits { static constexpr bool is_vector = false; };
template<> struct VectorTraits<Vec4f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec8f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec4d> : _VectorTraits { typedef double value_type; };
template<typename T> using EnableIfFP = std::enable_if_t<std::is_floating_point<T>::value>;
template<typename T> using EnableIfVec = std::enable_if_t<VectorTraits<T>::is_vector>;
template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;
// Actual variable template, finally:
template<typename T, typename Enabler = void> const T huge = T{ 0 };
template<typename T> const T huge<T, EnableIfFP<T> > = std::scalbn(1, EXP<T>);
template<typename T> const T huge<T, EnableIfVec<T> > = T{ huge<typename VectorTraits<T>::value_type> };
This could still be improved I think:
- It's verbose.
T
appears 4 times in each specialization's left-hand side. - Integral types (e.g.
huge<uint32_t>
) still compile with a nonsense0
value. I'd rather them not compile.
add a comment |
Leaving @max66's answer as the accepted one for the credit, but here's the specific solution I wound up with:
struct _VectorTraits { static constexpr bool is_vector = true; };
template<class T> struct VectorTraits : _VectorTraits { static constexpr bool is_vector = false; };
template<> struct VectorTraits<Vec4f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec8f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec4d> : _VectorTraits { typedef double value_type; };
template<typename T> using EnableIfFP = std::enable_if_t<std::is_floating_point<T>::value>;
template<typename T> using EnableIfVec = std::enable_if_t<VectorTraits<T>::is_vector>;
template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;
// Actual variable template, finally:
template<typename T, typename Enabler = void> const T huge = T{ 0 };
template<typename T> const T huge<T, EnableIfFP<T> > = std::scalbn(1, EXP<T>);
template<typename T> const T huge<T, EnableIfVec<T> > = T{ huge<typename VectorTraits<T>::value_type> };
This could still be improved I think:
- It's verbose.
T
appears 4 times in each specialization's left-hand side. - Integral types (e.g.
huge<uint32_t>
) still compile with a nonsense0
value. I'd rather them not compile.
Leaving @max66's answer as the accepted one for the credit, but here's the specific solution I wound up with:
struct _VectorTraits { static constexpr bool is_vector = true; };
template<class T> struct VectorTraits : _VectorTraits { static constexpr bool is_vector = false; };
template<> struct VectorTraits<Vec4f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec8f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec4d> : _VectorTraits { typedef double value_type; };
template<typename T> using EnableIfFP = std::enable_if_t<std::is_floating_point<T>::value>;
template<typename T> using EnableIfVec = std::enable_if_t<VectorTraits<T>::is_vector>;
template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;
// Actual variable template, finally:
template<typename T, typename Enabler = void> const T huge = T{ 0 };
template<typename T> const T huge<T, EnableIfFP<T> > = std::scalbn(1, EXP<T>);
template<typename T> const T huge<T, EnableIfVec<T> > = T{ huge<typename VectorTraits<T>::value_type> };
This could still be improved I think:
- It's verbose.
T
appears 4 times in each specialization's left-hand side. - Integral types (e.g.
huge<uint32_t>
) still compile with a nonsense0
value. I'd rather them not compile.
answered Dec 31 '18 at 9:27
ZachBZachB
5,31413159
5,31413159
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53982348%2fmultiple-variable-template-specializations-with-stdenable-if%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown