Enforcing function contract at compile time when possible
(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)
Let's say, we have a single-argument foo
, semantically defined as
int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.
Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.
Here are some potential routes which do not solve the problem:
- Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments
- Making function a
constexpr
- this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc insertsud2
instruction, which is not what I want.
c++
|
show 13 more comments
(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)
Let's say, we have a single-argument foo
, semantically defined as
int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.
Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.
Here are some potential routes which do not solve the problem:
- Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments
- Making function a
constexpr
- this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc insertsud2
instruction, which is not what I want.
c++
6
out of curiosity, why this Q is upvoted while linked-one is downvoted?
– apple apple
10 hours ago
1
@appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.
– YSC
10 hours ago
6
@YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.
– apple apple
10 hours ago
1
@appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).
– YSC
10 hours ago
3
@IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.
– SergeyA
9 hours ago
|
show 13 more comments
(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)
Let's say, we have a single-argument foo
, semantically defined as
int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.
Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.
Here are some potential routes which do not solve the problem:
- Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments
- Making function a
constexpr
- this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc insertsud2
instruction, which is not what I want.
c++
(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)
Let's say, we have a single-argument foo
, semantically defined as
int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.
Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.
Here are some potential routes which do not solve the problem:
- Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments
- Making function a
constexpr
- this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc insertsud2
instruction, which is not what I want.
c++
c++
edited 9 hours ago
asked 10 hours ago
SergeyA
41.3k53783
41.3k53783
6
out of curiosity, why this Q is upvoted while linked-one is downvoted?
– apple apple
10 hours ago
1
@appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.
– YSC
10 hours ago
6
@YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.
– apple apple
10 hours ago
1
@appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).
– YSC
10 hours ago
3
@IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.
– SergeyA
9 hours ago
|
show 13 more comments
6
out of curiosity, why this Q is upvoted while linked-one is downvoted?
– apple apple
10 hours ago
1
@appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.
– YSC
10 hours ago
6
@YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.
– apple apple
10 hours ago
1
@appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).
– YSC
10 hours ago
3
@IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.
– SergeyA
9 hours ago
6
6
out of curiosity, why this Q is upvoted while linked-one is downvoted?
– apple apple
10 hours ago
out of curiosity, why this Q is upvoted while linked-one is downvoted?
– apple apple
10 hours ago
1
1
@appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.
– YSC
10 hours ago
@appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.
– YSC
10 hours ago
6
6
@YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.
– apple apple
10 hours ago
@YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.
– apple apple
10 hours ago
1
1
@appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).
– YSC
10 hours ago
@appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).
– YSC
10 hours ago
3
3
@IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.
– SergeyA
9 hours ago
@IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.
– SergeyA
9 hours ago
|
show 13 more comments
3 Answers
3
active
oldest
votes
I got error with constexpr
when used in constant expression for:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
Demo
We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
Possibly with UDL with operator "" _c
to have 5_c
, 42_c
.
and then, add overload with that:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
So:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
As I said, arguments are not known to be constant inside the function, and if_constexpr
seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p
), so with MACRO, we can do the dispatch:
#define FOO(X) [&](){
if constexpr (__builtin_constant_p(X)) {
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
} else {
return foo(X);
}
}()
Demo
Note: Cannot use foo(int_c<X>{})
directly, even in if constexpr, as there is still some syntax check.
Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.
– SergeyA
5 hours ago
I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided
– SergeyA
5 hours ago
That's why I provide in my answer way to pass compile time argument (withint_c
) which allows to check at compile time , as they call it in constant expression.
– Jarod42
5 hours ago
Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.
– SergeyA
5 hours ago
Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )
– Jarod42
3 hours ago
add a comment |
It's not perfect and it requires us to use arguments in two different places, but it 'works':
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
We can call it like so:
foo<5>(); // does not compile
foo(5); // UB
foo<5>(5); // does not compile
foo<5>(10); // does not compile
foo<10>(5); // UB
foo(); // fine
foo<10>(); // fine
foo(10); // fine
2
No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.
– SergeyA
9 hours ago
1
Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>
– Fureeish
9 hours ago
You might add an additional runtime check that argument are equal or defaulted.
– Jarod42
3 hours ago
add a comment |
gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
these statements produce compile time error:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
while all others - runtime segfault (or ub if no nullptr
is used)
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%2f53933634%2fenforcing-function-contract-at-compile-time-when-possible%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
I got error with constexpr
when used in constant expression for:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
Demo
We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
Possibly with UDL with operator "" _c
to have 5_c
, 42_c
.
and then, add overload with that:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
So:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
As I said, arguments are not known to be constant inside the function, and if_constexpr
seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p
), so with MACRO, we can do the dispatch:
#define FOO(X) [&](){
if constexpr (__builtin_constant_p(X)) {
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
} else {
return foo(X);
}
}()
Demo
Note: Cannot use foo(int_c<X>{})
directly, even in if constexpr, as there is still some syntax check.
Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.
– SergeyA
5 hours ago
I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided
– SergeyA
5 hours ago
That's why I provide in my answer way to pass compile time argument (withint_c
) which allows to check at compile time , as they call it in constant expression.
– Jarod42
5 hours ago
Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.
– SergeyA
5 hours ago
Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )
– Jarod42
3 hours ago
add a comment |
I got error with constexpr
when used in constant expression for:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
Demo
We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
Possibly with UDL with operator "" _c
to have 5_c
, 42_c
.
and then, add overload with that:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
So:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
As I said, arguments are not known to be constant inside the function, and if_constexpr
seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p
), so with MACRO, we can do the dispatch:
#define FOO(X) [&](){
if constexpr (__builtin_constant_p(X)) {
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
} else {
return foo(X);
}
}()
Demo
Note: Cannot use foo(int_c<X>{})
directly, even in if constexpr, as there is still some syntax check.
Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.
– SergeyA
5 hours ago
I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided
– SergeyA
5 hours ago
That's why I provide in my answer way to pass compile time argument (withint_c
) which allows to check at compile time , as they call it in constant expression.
– Jarod42
5 hours ago
Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.
– SergeyA
5 hours ago
Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )
– Jarod42
3 hours ago
add a comment |
I got error with constexpr
when used in constant expression for:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
Demo
We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
Possibly with UDL with operator "" _c
to have 5_c
, 42_c
.
and then, add overload with that:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
So:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
As I said, arguments are not known to be constant inside the function, and if_constexpr
seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p
), so with MACRO, we can do the dispatch:
#define FOO(X) [&](){
if constexpr (__builtin_constant_p(X)) {
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
} else {
return foo(X);
}
}()
Demo
Note: Cannot use foo(int_c<X>{})
directly, even in if constexpr, as there is still some syntax check.
I got error with constexpr
when used in constant expression for:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
Demo
We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
Possibly with UDL with operator "" _c
to have 5_c
, 42_c
.
and then, add overload with that:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
So:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
As I said, arguments are not known to be constant inside the function, and if_constexpr
seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p
), so with MACRO, we can do the dispatch:
#define FOO(X) [&](){
if constexpr (__builtin_constant_p(X)) {
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
} else {
return foo(X);
}
}()
Demo
Note: Cannot use foo(int_c<X>{})
directly, even in if constexpr, as there is still some syntax check.
edited 3 hours ago
answered 6 hours ago
Jarod42
112k1299179
112k1299179
Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.
– SergeyA
5 hours ago
I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided
– SergeyA
5 hours ago
That's why I provide in my answer way to pass compile time argument (withint_c
) which allows to check at compile time , as they call it in constant expression.
– Jarod42
5 hours ago
Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.
– SergeyA
5 hours ago
Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )
– Jarod42
3 hours ago
add a comment |
Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.
– SergeyA
5 hours ago
I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided
– SergeyA
5 hours ago
That's why I provide in my answer way to pass compile time argument (withint_c
) which allows to check at compile time , as they call it in constant expression.
– Jarod42
5 hours ago
Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.
– SergeyA
5 hours ago
Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )
– Jarod42
3 hours ago
Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.
– SergeyA
5 hours ago
Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.
– SergeyA
5 hours ago
I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided
– SergeyA
5 hours ago
I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided
– SergeyA
5 hours ago
That's why I provide in my answer way to pass compile time argument (with
int_c
) which allows to check at compile time , as they call it in constant expression.– Jarod42
5 hours ago
That's why I provide in my answer way to pass compile time argument (with
int_c
) which allows to check at compile time , as they call it in constant expression.– Jarod42
5 hours ago
Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.
– SergeyA
5 hours ago
Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.
– SergeyA
5 hours ago
Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )
– Jarod42
3 hours ago
Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )
– Jarod42
3 hours ago
add a comment |
It's not perfect and it requires us to use arguments in two different places, but it 'works':
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
We can call it like so:
foo<5>(); // does not compile
foo(5); // UB
foo<5>(5); // does not compile
foo<5>(10); // does not compile
foo<10>(5); // UB
foo(); // fine
foo<10>(); // fine
foo(10); // fine
2
No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.
– SergeyA
9 hours ago
1
Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>
– Fureeish
9 hours ago
You might add an additional runtime check that argument are equal or defaulted.
– Jarod42
3 hours ago
add a comment |
It's not perfect and it requires us to use arguments in two different places, but it 'works':
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
We can call it like so:
foo<5>(); // does not compile
foo(5); // UB
foo<5>(5); // does not compile
foo<5>(10); // does not compile
foo<10>(5); // UB
foo(); // fine
foo<10>(); // fine
foo(10); // fine
2
No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.
– SergeyA
9 hours ago
1
Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>
– Fureeish
9 hours ago
You might add an additional runtime check that argument are equal or defaulted.
– Jarod42
3 hours ago
add a comment |
It's not perfect and it requires us to use arguments in two different places, but it 'works':
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
We can call it like so:
foo<5>(); // does not compile
foo(5); // UB
foo<5>(5); // does not compile
foo<5>(10); // does not compile
foo<10>(5); // UB
foo(); // fine
foo<10>(); // fine
foo(10); // fine
It's not perfect and it requires us to use arguments in two different places, but it 'works':
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
We can call it like so:
foo<5>(); // does not compile
foo(5); // UB
foo<5>(5); // does not compile
foo<5>(10); // does not compile
foo<10>(5); // UB
foo(); // fine
foo<10>(); // fine
foo(10); // fine
answered 9 hours ago
Fureeish
2,97721024
2,97721024
2
No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.
– SergeyA
9 hours ago
1
Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>
– Fureeish
9 hours ago
You might add an additional runtime check that argument are equal or defaulted.
– Jarod42
3 hours ago
add a comment |
2
No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.
– SergeyA
9 hours ago
1
Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>
– Fureeish
9 hours ago
You might add an additional runtime check that argument are equal or defaulted.
– Jarod42
3 hours ago
2
2
No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.
– SergeyA
9 hours ago
No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.
– SergeyA
9 hours ago
1
1
Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>
– Fureeish
9 hours ago
Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>
– Fureeish
9 hours ago
You might add an additional runtime check that argument are equal or defaulted.
– Jarod42
3 hours ago
You might add an additional runtime check that argument are equal or defaulted.
– Jarod42
3 hours ago
add a comment |
gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
these statements produce compile time error:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
while all others - runtime segfault (or ub if no nullptr
is used)
add a comment |
gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
these statements produce compile time error:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
while all others - runtime segfault (or ub if no nullptr
is used)
add a comment |
gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
these statements produce compile time error:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
while all others - runtime segfault (or ub if no nullptr
is used)
gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
these statements produce compile time error:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
while all others - runtime segfault (or ub if no nullptr
is used)
answered 1 hour ago
Iłya Bursov
17.9k32543
17.9k32543
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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%2f53933634%2fenforcing-function-contract-at-compile-time-when-possible%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
6
out of curiosity, why this Q is upvoted while linked-one is downvoted?
– apple apple
10 hours ago
1
@appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.
– YSC
10 hours ago
6
@YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.
– apple apple
10 hours ago
1
@appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).
– YSC
10 hours ago
3
@IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.
– SergeyA
9 hours ago